GroupBy splits our datatable by group
(by ...GroupBy)
| 72 | |
| 73 | // GroupBy splits our datatable by group |
| 74 | func (dt *DataTable) GroupBy(by ...GroupBy) (*Groups, error) { |
| 75 | if len(by) == 0 { |
| 76 | return nil, ErrNoGroupBy |
| 77 | } |
| 78 | |
| 79 | var groups []*group |
| 80 | gindex := make(map[uint64]int) |
| 81 | |
| 82 | for pos := 0; pos < dt.nrows; pos++ { |
| 83 | row := dt.Row(pos) |
| 84 | buf := bytes.NewBuffer(nil) |
| 85 | enc := gob.NewEncoder(buf) |
| 86 | |
| 87 | buckets := make([]interface{}, len(by)) |
| 88 | |
| 89 | for i, k := range by { |
| 90 | k := &k |
| 91 | if v, ok := k.Keyer(row); ok { |
| 92 | buckets[i] = v |
| 93 | enc.Encode(v) |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | hash := xxhash.Sum64(buf.Bytes()) |
| 98 | |
| 99 | if at, ok := gindex[hash]; ok { |
| 100 | groups[at].Rows = append(groups[at].Rows, pos) |
| 101 | } else { |
| 102 | gindex[hash] = len(groups) |
| 103 | groups = append(groups, &group{ |
| 104 | Key: hash, |
| 105 | Buckets: buckets, |
| 106 | Rows: []int{pos}, |
| 107 | }) |
| 108 | } |
| 109 | } |
| 110 | return &Groups{dt: dt, groups: groups, by: by}, nil |
| 111 | } |
| 112 | |
| 113 | // Aggregate aggregates some field |
| 114 | func (dt *DataTable) Aggregate(by ...AggregateBy) (*DataTable, error) { |