Допустим, у меня есть структура
type row struct {
f1, f2, f3 string
v int64
}
Мы можем представить ее как строку в таблице.
Кроме того, мне нужно реализовать функцию, которая выполняет агрегирование, как этот запрос:
SELECT f1, f2, f3, SUM(v) FROM table GROUP BY f1, f2, f3
Итак, я должен реализовать функцию:
type key struct {
f1, f2, f3 string
}
func aggregate(t []row) map[key]int64
или, если это может быть
func aggregate(t []row) map[string]row
, где ключ карты, например, f1 + f2+ f3
func aggregate(t []row) []row
также работает, если результат будет включать уникальные комбинации f1, f2, f3 (DISTINCT f1, f2, f3)
У меня есть два варианта:
func aggregate1(t []row) map[key]int64 {
res := map[key]int64{}
for _, r := range t {
res[key{r.f1, r.f2, r.f3}] += r.v
}
return res
}
func aggregate2(t []row) map[string]*row {
res := map[string]*row{}
for _, r := range t {
var sb strings.Builder
sb.WriteString(r.f1)
sb.WriteString("#")
sb.WriteString(r.f2)
sb.WriteString("#")
sb.WriteString(r.f3)
id := sb.String()
t := res[id]
if t == nil {
t = &row{f1: r.f1, f2: r.f2, f3: r.f3, v: 0}
res[id] = t
}
t.v += r.v
}
return res
}
Первый вариант тратит слишком много времени на https://golang.org/pkg/runtime/?m=all#mapassign (runtime.mapassign)
Идея второго варианта заключается в использовании более быстрых https://golang.org/pkg/runtime/?m=all#mapassign_faststr (runtime.mapassign_faststr), ноstrings.Builder.WriteString устраняет все преимущества runtime.mapassign_faststr: (*
Итак, можете ли вы предложить больше идей о том, как реализовать это агрегирование?
Я думаю о том, как эффективно рассчитать "id""во втором варианте. Он должен быть уникальным. Мой вариант уникален, потому что f1, f2 и f3 не могут включать"#" персонаж.