-
Notifications
You must be signed in to change notification settings - Fork 225
/
aggregate.go
158 lines (135 loc) · 5.13 KB
/
aggregate.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package linq
// Aggregate applies an accumulator function over a sequence.
//
// Aggregate method makes it simple to perform a calculation over a sequence of
// values. This method works by calling f() one time for each element in source
// except the first one. Each time f() is called, Aggregate passes both the
// element from the sequence and an aggregated value (as the first argument to
// f()). The first element of source is used as the initial aggregate value. The
// result of f() replaces the previous aggregated value.
//
// Aggregate returns the final result of f().
func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{} {
next := q.Iterate()
result, any := next()
if !any {
return nil
}
for current, ok := next(); ok; current, ok = next() {
result = f(result, current)
}
return result
}
// AggregateT is the typed version of Aggregate.
//
// - f is of type: func(TSource, TSource) TSource
//
// NOTE: Aggregate has better performance than AggregateT.
func (q Query) AggregateT(f interface{}) interface{} {
fGenericFunc, err := newGenericFunc(
"AggregateT", "f", f,
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
)
if err != nil {
panic(err)
}
fFunc := func(result interface{}, current interface{}) interface{} {
return fGenericFunc.Call(result, current)
}
return q.Aggregate(fFunc)
}
// AggregateWithSeed applies an accumulator function over a sequence. The
// specified seed value is used as the initial accumulator value.
//
// Aggregate method makes it simple to perform a calculation over a sequence of
// values. This method works by calling f() one time for each element in source
// except the first one. Each time f() is called, Aggregate passes both the
// element from the sequence and an aggregated value (as the first argument to
// f()). The value of the seed parameter is used as the initial aggregate value.
// The result of f() replaces the previous aggregated value.
//
// Aggregate returns the final result of f().
func (q Query) AggregateWithSeed(seed interface{},
f func(interface{}, interface{}) interface{}) interface{} {
next := q.Iterate()
result := seed
for current, ok := next(); ok; current, ok = next() {
result = f(result, current)
}
return result
}
// AggregateWithSeedT is the typed version of AggregateWithSeed.
//
// - f is of type "func(TAccumulate, TSource) TAccumulate"
//
// NOTE: AggregateWithSeed has better performance than
// AggregateWithSeedT.
func (q Query) AggregateWithSeedT(seed interface{},
f interface{}) interface{} {
fGenericFunc, err := newGenericFunc(
"AggregateWithSeed", "f", f,
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
)
if err != nil {
panic(err)
}
fFunc := func(result interface{}, current interface{}) interface{} {
return fGenericFunc.Call(result, current)
}
return q.AggregateWithSeed(seed, fFunc)
}
// AggregateWithSeedBy applies an accumulator function over a sequence. The
// specified seed value is used as the initial accumulator value, and the
// specified function is used to select the result value.
//
// Aggregate method makes it simple to perform a calculation over a sequence of
// values. This method works by calling f() one time for each element in source.
// Each time func is called, Aggregate passes both the element from the sequence
// and an aggregated value (as the first argument to func). The value of the
// seed parameter is used as the initial aggregate value. The result of func
// replaces the previous aggregated value.
//
// The final result of func is passed to resultSelector to obtain the final
// result of Aggregate.
func (q Query) AggregateWithSeedBy(seed interface{},
f func(interface{}, interface{}) interface{},
resultSelector func(interface{}) interface{}) interface{} {
next := q.Iterate()
result := seed
for current, ok := next(); ok; current, ok = next() {
result = f(result, current)
}
return resultSelector(result)
}
// AggregateWithSeedByT is the typed version of AggregateWithSeedBy.
//
// - f is of type "func(TAccumulate, TSource) TAccumulate"
// - resultSelectorFn is of type "func(TAccumulate) TResult"
//
// NOTE: AggregateWithSeedBy has better performance than
// AggregateWithSeedByT.
func (q Query) AggregateWithSeedByT(seed interface{},
f interface{},
resultSelectorFn interface{}) interface{} {
fGenericFunc, err := newGenericFunc(
"AggregateWithSeedByT", "f", f,
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
)
if err != nil {
panic(err)
}
fFunc := func(result interface{}, current interface{}) interface{} {
return fGenericFunc.Call(result, current)
}
resultSelectorGenericFunc, err := newGenericFunc(
"AggregateWithSeedByT", "resultSelectorFn", resultSelectorFn,
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
)
if err != nil {
panic(err)
}
resultSelectorFunc := func(result interface{}) interface{} {
return resultSelectorGenericFunc.Call(result)
}
return q.AggregateWithSeedBy(seed, fFunc, resultSelectorFunc)
}