aboutsummaryrefslogtreecommitdiff
path: root/cmd/seq-stat/main.go
blob: 75bb0a3be9598647a7368297f4c5311219dea532 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

var ticks = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}

func histogram(sequence []float64) []rune {
	if len(sequence) == 0 {
		return []rune{}
	}

	minVal := sequence[0]
	maxVal := sequence[0]

	for _, v := range sequence {
		if v < minVal {
			minVal = v
		}
		if v > maxVal {
			maxVal = v
		}
	}

	scale := (maxVal - minVal) * 256 / float64(len(ticks)-1)
	if scale < 1 {
		scale = 1
	}

	result := make([]rune, len(sequence))
	for i, v := range sequence {
		index := int(((v - minVal) * 256) / scale)
		if index >= len(ticks) {
			index = len(ticks) - 1
		}
		result[i] = ticks[index]
	}

	return result
}

func parseNumbers(input string) ([]float64, error) {
	fields := strings.Fields(input)
	numbers := make([]float64, 0, len(fields))

	for _, field := range fields {
		num, err := strconv.ParseFloat(field, 64)
		if err != nil {
			return nil, fmt.Errorf("invalid number: %s", field)
		}
		numbers = append(numbers, num)
	}

	return numbers, nil
}

func readFromStdin() ([]float64, error) {
	var numbers []float64
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		lineNumbers, err := parseNumbers(line)
		if err != nil {
			return nil, err
		}
		numbers = append(numbers, lineNumbers...)
	}

	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("error reading from stdin: %v", err)
	}

	return numbers, nil
}

func main() {
	var numbers []float64
	var err error

	if len(os.Args) > 1 {
		numbers = make([]float64, 0, len(os.Args)-1)
		for _, arg := range os.Args[1:] {
			num, parseErr := strconv.ParseFloat(arg, 64)
			if parseErr != nil {
				fmt.Fprintf(os.Stderr, "Invalid number: %s\n", arg)
				os.Exit(1)
			}
			numbers = append(numbers, num)
		}
	} else {
		numbers, err = readFromStdin()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
			os.Exit(1)
		}

		if len(numbers) == 0 {
			fmt.Fprintln(os.Stderr, "No numbers provided")
			os.Exit(1)
		}
	}

	h := histogram(numbers)
	fmt.Println(string(h))
}