11package weaklinq
22
3- import "reflect"
4-
53//----------------------------------------------------------------------------//
64// Joining //
75//----------------------------------------------------------------------------//
86
97////////////////////////////////////////////////////////////////////////////////
108
9+ // joinType is an enum that represents the type of join to perform.
10+ type joinType int
11+
12+ const (
13+ InnerJoin joinType = iota
14+ LeftJoin
15+ RightJoin
16+ FullOuterJoin
17+ )
18+
19+ ////////////////////////////////////////////////////////////////////////////////
20+
1121// JoinIterable is a specialized iterable that includes a right iterable, a key
1222// selector for the left iterable, and a key selector for the right iterable.
1323// These selectors are stored until the collection is iterated, and then
@@ -17,6 +27,7 @@ type JoinIterable[T any] struct {
1727 rightIterable Iterable [any ]
1828 keySelector func (T ) any
1929 rightKeySelector func (any ) any
30+ joinType joinType
2031}
2132
2233/////////////////////////////////////////////////////////////////////////////////
@@ -43,6 +54,7 @@ func defaultJoinIterable[T any](iterable Iterable[T], joinIterable Iterable[any]
4354 rightIterable : joinIterable ,
4455 keySelector : identitySelector [T ],
4556 rightKeySelector : identitySelector [any ],
57+ joinType : InnerJoin ,
4658 }
4759}
4860
@@ -61,25 +73,43 @@ func (iterable Iterable[T]) Join(joinIterable Iterable[any]) DeferredJoinIterabl
6173
6274////////////////////////////////////////////////////////////////////////////////
6375
64- // JoinSlice returns a new DeferredJoinIterable that will join the items of the given slice
65- func (iterable Iterable [T ]) JoinSlice (joinSlice any ) DeferredJoinIterable [T ] {
76+ // LeftJoin returns a new DeferredJoinIterable that will perform a left join
77+ // on the given iterable.
78+ func (iterable Iterable [T ]) LeftJoin (joinIterable Iterable [any ]) DeferredJoinIterable [T ] {
6679
67- if reflect .TypeOf (joinSlice ).Kind () != reflect .Slice {
68- panic ("'joinSlice' must be a slice" )
69- }
80+ defaultIterable := defaultJoinIterable (iterable , joinIterable )
81+ defaultIterable .joinType = LeftJoin
82+ return DeferredJoinIterable [T ](defaultIterable )
83+ }
7084
71- joinIterable := Iterable [any ]{
72- Seq : func (yield func (any ) bool ) {
73- s := reflect .ValueOf (joinSlice )
74- for i := 0 ; i < s .Len (); i ++ {
75- if ! yield (s .Index (i ).Interface ()) {
76- return
77- }
78- }
79- },
80- }
85+ ////////////////////////////////////////////////////////////////////////////////
86+
87+ // RightJoin returns a new DeferredJoinIterable that will perform a right join
88+ // on the given iterable.
89+ func (iterable Iterable [T ]) RightJoin (joinIterable Iterable [any ]) DeferredJoinIterable [T ] {
8190
82- return iterable .Join (joinIterable )
91+ defaultIterable := defaultJoinIterable (iterable , joinIterable )
92+ defaultIterable .joinType = RightJoin
93+ return DeferredJoinIterable [T ](defaultIterable )
94+ }
95+
96+ ////////////////////////////////////////////////////////////////////////////////
97+
98+ // FullOuterJoin returns a new DeferredJoinIterable that will perform a full
99+ // outer join on the given iterable.
100+ func (iterable Iterable [T ]) FullOuterJoin (joinIterable Iterable [any ]) DeferredJoinIterable [T ] {
101+
102+ defaultIterable := defaultJoinIterable (iterable , joinIterable )
103+ defaultIterable .joinType = FullOuterJoin
104+ return DeferredJoinIterable [T ](defaultIterable )
105+ }
106+
107+ ////////////////////////////////////////////////////////////////////////////////
108+
109+ // JoinSlice returns a new DeferredJoinIterable that will join the items of the given slice
110+ func (iterable Iterable [T ]) JoinSlice (joinSlice []T ) DeferredJoinIterable [T ] {
111+
112+ return iterable .Join (From (joinSlice ).AsAny ())
83113
84114 /*
85115 linq.From([]T{...}).
@@ -89,6 +119,46 @@ func (iterable Iterable[T]) JoinSlice(joinSlice any) DeferredJoinIterable[T] {
89119
90120////////////////////////////////////////////////////////////////////////////////
91121
122+ // LeftJoinSlice returns a new DeferredJoinIterable that will perform a left
123+ // join on the given slice.
124+ func (iterable Iterable [T ]) LeftJoinSlice (joinSlice []T ) DeferredJoinIterable [T ] {
125+
126+ return iterable .LeftJoin (From (joinSlice ).AsAny ())
127+
128+ /*
129+ linq.From([]T{...}).
130+ LeftJoinSlice([]TRight{...})
131+ */
132+ }
133+
134+ // RightJoinSlice returns a new DeferredJoinIterable that will perform a right
135+ // join on the given slice.
136+ func (iterable Iterable [T ]) RightJoinSlice (joinSlice []T ) DeferredJoinIterable [T ] {
137+
138+ return iterable .RightJoin (From (joinSlice ).AsAny ())
139+
140+ /*
141+ linq.From([]T{...}).
142+ RightJoinSlice([]TRight{...})
143+ */
144+ }
145+
146+ ////////////////////////////////////////////////////////////////////////////////
147+
148+ // FullOuterJoinSlice returns a new DeferredJoinIterable that will perform a
149+ // full outer join on the given slice.
150+ func (iterable Iterable [T ]) FullOuterJoinSlice (joinSlice []T ) DeferredJoinIterable [T ] {
151+
152+ return iterable .FullOuterJoin (From (joinSlice ).AsAny ())
153+
154+ /*
155+ linq.From([]T{...}).
156+ FullOuterJoinSlice([]TRight{...})
157+ */
158+ }
159+
160+ ////////////////////////////////////////////////////////////////////////////////
161+
92162// OnThis sets the key selector functions for both left and right iterables.
93163func (iterable DeferredJoinIterable [T ]) OnThis (keySelector func (T ) any ) DeferredJoinIterable [T ] {
94164
@@ -178,21 +248,48 @@ func (iterable DeferredJoinIterable[T]) AsThis(joinSelector func(T, any) any) It
178248
179249 return Iterable [any ]{
180250 Seq : func (yield func (any ) bool ) {
181- iterable . itemIterable . Seq ( func ( leftItem T ) bool {
251+ matchedRightItems := make ( map [ any ] bool )
182252
253+ // Process left items
254+ iterable .itemIterable .Seq (func (leftItem T ) bool {
183255 leftKey := iterable .keySelector (leftItem )
256+ rightItems , hasMatch := rightKeysToRightItems [leftKey ]
184257
185- if rightItems , ok := rightKeysToRightItems [leftKey ]; ok {
258+ if hasMatch {
259+ // Inner, Left, Right, or Full Join with matches
186260 for _ , rightItem := range rightItems {
261+ matchedRightItems [rightItem ] = true
187262 result := joinSelector (leftItem , rightItem )
188263 if ! yield (result ) {
189264 return false
190265 }
191266 }
267+ } else if iterable .joinType == LeftJoin || iterable .joinType == FullOuterJoin {
268+ // Left or Full Join with no match - yield left with nil right
269+ result := joinSelector (leftItem , nil )
270+ if ! yield (result ) {
271+ return false
272+ }
192273 }
193274
194275 return true
195276 })
277+
278+ // Handle unmatched right items for Right and Full Join
279+ if iterable .joinType == RightJoin || iterable .joinType == FullOuterJoin {
280+ for _ , rightItems := range rightKeysToRightItems {
281+ for _ , rightItem := range rightItems {
282+ if ! matchedRightItems [rightItem ] {
283+ // Yield nil left with unmatched right
284+ var zeroLeft T
285+ result := joinSelector (zeroLeft , rightItem )
286+ if ! yield (result ) {
287+ return
288+ }
289+ }
290+ }
291+ }
292+ }
196293 },
197294 }
198295
0 commit comments