-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgroupjoin.go
53 lines (47 loc) · 1.73 KB
/
groupjoin.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
package flinx
// GroupJoin correlates the elements of two collections based on key equality,
// and groups the results.
//
// This method produces hierarchical results, which means that elements from
// outer query are paired with collections of matching elements from inner.
// GroupJoin enables you to base your results on a whole set of matches for each
// element of outer query.
//
// The resultSelector function is called only one time for each outer element
// together with a collection of all the inner elements that match the outer
// element. This differs from the Join method, in which the result selector
// function is invoked on pairs that contain one element from outer and one
// element from inner.
//
// GroupJoin preserves the order of the elements of outer, and for each element
// of outer, the order of the matching elements from inner.
func GroupJoin[T, V, O any, K comparable](
outerKeySelector func(T) K,
innerKeySelector func(V) K,
resultSelector func(outer T, inners []V) O) func(q Query[T], inner Query[V]) Query[O] {
return func(q Query[T], inner Query[V]) Query[O] {
return Query[O]{
Iterate: func() Iterator[O] {
outernext := q.Iterate()
innernext := inner.Iterate()
innerLookup := make(map[K][]V)
for innerItem, ok := innernext(); ok; innerItem, ok = innernext() {
innerKey := innerKeySelector(innerItem)
innerLookup[innerKey] = append(innerLookup[innerKey], innerItem)
}
return func() (item O, ok bool) {
var tItem T
if tItem, ok = outernext(); !ok {
return
}
if group, has := innerLookup[outerKeySelector(tItem)]; !has {
item = resultSelector(tItem, []V{})
} else {
item = resultSelector(tItem, group)
}
return
}
},
}
}
}