File: main.go

package info (click to toggle)
golang-text 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 128 kB
  • sloc: makefile: 5
file content (112 lines) | stat: -rw-r--r-- 1,728 bytes parent folder | download | duplicates (3)
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
package main

// TODO(kr): tests

import (
	"bufio"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"
)

type agg interface {
	merge(string)
	String() string
}

var (
	key     = 0
	funcmap = make(map[int]func(init, arg string) agg)
	argmap  = make(map[int]string)
	symtab  = map[string]func(init, arg string) agg{
		"first":  first,
		"last":   last,
		"prefix": prefix,
		"sample": sample,
		"join":   join,
		"smin":   smin,
		"smax":   smax,
		"min":    min,
		"max":    max,
		"sum":    sum,
		"mean":   mean,
		"count":  count,
		"const":  constf,
		"drop":   nil,
	}
)

func main() {
	log.SetPrefix("agg: ")
	log.SetFlags(0)
	rand.Seed(time.Now().UnixNano())
	for i, sym := range os.Args[1:] {
		if p := strings.IndexByte(sym, ':'); p >= 0 {
			sym, argmap[i] = sym[:p], sym[p+1:]
		}
		if sym == "key" {
			key, sym = i, "first"
		}
		f, ok := symtab[sym]
		if !ok {
			log.Fatalf("bad function: %q", sym)
		}
		funcmap[i] = f
	}

	sc := bufio.NewScanner(os.Stdin)
	var g *group
	for sc.Scan() {
		ss := strings.Fields(sc.Text())
		if !matches(g, ss) {
			emit(g)
			g = &group{key: ss[key]}
		}
		mergeLine(g, ss)
	}
	emit(g)
}

type group struct {
	key string
	agg []agg
}

func matches(g *group, ss []string) bool {
	return g != nil && g.key == ss[key]
}

func emit(g *group) {
	if g == nil {
		return
	}
	rest := false
	for i, a := range g.agg {
		if f, ok := funcmap[i]; ok && f == nil {
			continue
		}
		if rest {
			fmt.Print("\t")
		}
		rest = true
		fmt.Print(a)
	}
	fmt.Println()
}

func mergeLine(g *group, ss []string) {
	for i, s := range ss {
		if i >= len(g.agg) {
			f := funcmap[i]
			if f == nil {
				f = first
			}
			g.agg = append(g.agg, f(s, argmap[i]))
		} else {
			g.agg[i].merge(s)
		}
	}
}