-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuncs_grouping.go
106 lines (97 loc) · 2.99 KB
/
funcs_grouping.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
package handy
import (
"github.com/hsldymq/goiter"
"iter"
)
type Joined[T1, T2 any] struct {
Outer T1
Inner T2
}
func Join[OuterT, InnerT any, K comparable](
outer Iterable[OuterT],
inner Iterable[InnerT],
outerKeySelector func(OuterT) K,
innerKeySelector func(InnerT) K,
) Enumerable[*Joined[OuterT, InnerT]] {
seq := func(yield func(*Joined[OuterT, InnerT]) bool) {
next, stop := iter.Pull(outer.Iter())
defer stop()
outerElem, ok := next()
if !ok {
return
}
group := groupIterableToMap[InnerT, K](inner, innerKeySelector)
for ok {
innerElems, hasAny := group[outerKeySelector(outerElem)]
if hasAny {
for _, innerElem := range innerElems {
combined := &Joined[OuterT, InnerT]{
Outer: outerElem,
Inner: innerElem,
}
if !yield(combined) {
return
}
}
}
outerElem, ok = next()
}
}
return NewEnumerator(seq)
}
func JoinAs[OuterT, InnerT any, K comparable, ResultT any](
outer Iterable[OuterT],
inner Iterable[InnerT],
outerKeySelector func(OuterT) K,
innerKeySelector func(InnerT) K,
transformer func(OuterT, InnerT) ResultT,
) Enumerable[ResultT] {
joinedSeq := Join(outer, inner, outerKeySelector, innerKeySelector).Iter()
transformedSeq := goiter.Transform(joinedSeq, func(combined *Joined[OuterT, InnerT]) ResultT {
return transformer(combined.Outer, combined.Inner)
})
return NewEnumerator(transformedSeq)
}
func GroupJoin[OuterT, InnerT any, K comparable](
outer Iterable[OuterT],
inner Iterable[InnerT],
outerKeySelector func(OuterT) K,
innerKeySelector func(InnerT) K,
) Enumerable[*Joined[OuterT, Enumerable[InnerT]]] {
seq := func(yield func(joined *Joined[OuterT, Enumerable[InnerT]]) bool) {
next, stop := iter.Pull(outer.Iter())
defer stop()
outerElem, ok := next()
if !ok {
return
}
group := groupIterableToMap[InnerT, K](inner, innerKeySelector)
for ok {
innerElems, hasAny := group[outerKeySelector(outerElem)]
if hasAny {
combined := &Joined[OuterT, Enumerable[InnerT]]{
Outer: outerElem,
Inner: NewEnumerator(goiter.SliceElems(innerElems)),
}
if !yield(combined) {
return
}
}
outerElem, ok = next()
}
}
return NewEnumerator(seq)
}
func groupIterableToMap[T any, K comparable](iterable Iterable[T], keySelector func(T) K) map[any][]T {
m := map[any][]T{}
next, stop := iter.Pull(iterable.Iter())
defer stop()
for {
v, ok := next()
if !ok {
return m
}
k := keySelector(v)
m[k] = append(m[k], v)
}
}