1
+ #region License and Terms
2
+ // MoreLINQ - Extensions to LINQ to Objects
3
+ // Copyright (c) 2008 Jonathan Skeet. All rights reserved.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+ #endregion
17
+
18
+ namespace MoreLinq
19
+ {
20
+ #region Imports
21
+
22
+ using System ;
23
+ using System . Collections . Generic ;
24
+ using System . Diagnostics ;
25
+
26
+ #endregion
27
+
28
+ public static partial class MoreEnumerable
29
+ {
30
+ /// <summary>
31
+ /// Merges two ordered sequences into one. Where the elements equal
32
+ /// in both sequences, the element from the first sequence is
33
+ /// returned in the resulting sequence.
34
+ /// </summary>
35
+ /// <remarks>
36
+ /// This method uses deferred execution. The behavior is undefined
37
+ /// if the sequences are unordered as inputs.
38
+ /// </remarks>
39
+
40
+ public static IEnumerable < T > OrderedMerge < T > (
41
+ this IEnumerable < T > first ,
42
+ IEnumerable < T > second )
43
+ {
44
+ return OrderedMerge ( first , second , null ) ;
45
+ }
46
+
47
+ /// <summary>
48
+ /// Merges two ordered sequences into one with an additional
49
+ /// parameter specifying how to compare the elements of the
50
+ /// sequences. Where the elements equal in both sequences, the
51
+ /// element from the first sequence is returned in the resulting
52
+ /// sequence.
53
+ /// </summary>
54
+ /// <remarks>
55
+ /// This method uses deferred execution. The behavior is undefined
56
+ /// if the sequences are unordered as inputs.
57
+ /// </remarks>
58
+
59
+ public static IEnumerable < T > OrderedMerge < T > (
60
+ this IEnumerable < T > first ,
61
+ IEnumerable < T > second ,
62
+ IComparer < T > comparer )
63
+ {
64
+ return OrderedMerge ( first , second , e => e , f => f , s => s , ( a , _ ) => a , comparer ) ;
65
+ }
66
+
67
+ /// <summary>
68
+ /// Merges two ordered sequences into one with an additional
69
+ /// parameter specifying the element key by which the sequences are
70
+ /// ordered. Where the keys equal in both sequences, the
71
+ /// element from the first sequence is returned in the resulting
72
+ /// sequence.
73
+ /// </summary>
74
+ /// <remarks>
75
+ /// This method uses deferred execution. The behavior is undefined
76
+ /// if the sequences are unordered (by key) as inputs.
77
+ /// </remarks>
78
+
79
+ public static IEnumerable < T > OrderedMerge < T , TKey > (
80
+ this IEnumerable < T > first ,
81
+ IEnumerable < T > second ,
82
+ Func < T , TKey > keySelector )
83
+ {
84
+ return OrderedMerge ( first , second , keySelector , a => a , b => b , ( a , _ ) => a , null ) ;
85
+ }
86
+
87
+ /// <summary>
88
+ /// Merges two ordered sequences into one. Additional parameters
89
+ /// specify the element key by which the sequences are ordered,
90
+ /// the result when element is found in first sequence but not in
91
+ /// the second, the result when element is found in second sequence
92
+ /// but not in the first and the result when elements are found in
93
+ /// both sequences.
94
+ /// </summary>
95
+ /// <remarks>
96
+ /// This method uses deferred execution. The behavior is undefined
97
+ /// if the sequences are unordered (by key) as inputs.
98
+ /// </remarks>
99
+
100
+ public static IEnumerable < TResult > OrderedMerge < T , TKey , TResult > (
101
+ this IEnumerable < T > first ,
102
+ IEnumerable < T > second ,
103
+ Func < T , TKey > keySelector ,
104
+ Func < T , TResult > firstSelector ,
105
+ Func < T , TResult > secondSelector ,
106
+ Func < T , T , TResult > bothSelector )
107
+ {
108
+ return OrderedMerge ( first , second , keySelector , firstSelector , secondSelector , bothSelector , null ) ;
109
+ }
110
+
111
+ /// <summary>
112
+ /// Merges two ordered sequences into one. Additional parameters
113
+ /// specify the element key by which the sequences are ordered,
114
+ /// the result when element is found in first sequence but not in
115
+ /// the second, the result when element is found in second sequence
116
+ /// but not in the first, the result when elements are found in
117
+ /// both sequences and a method for comparing keys.
118
+ /// </summary>
119
+ /// <remarks>
120
+ /// This method uses deferred execution. The behavior is undefined
121
+ /// if the sequences are unordered (by key) as inputs.
122
+ /// </remarks>
123
+
124
+ public static IEnumerable < TResult > OrderedMerge < T , TKey , TResult > (
125
+ this IEnumerable < T > first ,
126
+ IEnumerable < T > second ,
127
+ Func < T , TKey > keySelector ,
128
+ Func < T , TResult > firstSelector ,
129
+ Func < T , TResult > secondSelector ,
130
+ Func < T , T , TResult > bothSelector ,
131
+ IComparer < TKey > comparer )
132
+ {
133
+ return OrderedMerge ( first , second , keySelector , keySelector , firstSelector , secondSelector , bothSelector , comparer ) ;
134
+ }
135
+
136
+ /// <summary>
137
+ /// Merges two heterogeneous sequences ordered by a common key type
138
+ /// into a homogeneous one. Additional parameters specify the
139
+ /// element key by which the sequences are ordered, the result when
140
+ /// element is found in first sequence but not in the second and
141
+ /// the result when element is found in second sequence but not in
142
+ /// the first, the result when elements are found in both sequences.
143
+ /// </summary>
144
+ /// <remarks>
145
+ /// This method uses deferred execution. The behavior is undefined
146
+ /// if the sequences are unordered (by key) as inputs.
147
+ /// </remarks>
148
+
149
+ public static IEnumerable < TResult > OrderedMerge < TFirst , TSecond , TKey , TResult > (
150
+ this IEnumerable < TFirst > first ,
151
+ IEnumerable < TSecond > second ,
152
+ Func < TFirst , TKey > firstKeySelector ,
153
+ Func < TSecond , TKey > secondKeySelector ,
154
+ Func < TFirst , TResult > firstSelector ,
155
+ Func < TSecond , TResult > secondSelector ,
156
+ Func < TFirst , TSecond , TResult > bothSelector )
157
+ {
158
+ return OrderedMerge ( first , second , firstKeySelector , secondKeySelector , firstSelector , secondSelector , bothSelector , null ) ;
159
+ }
160
+
161
+ /// <summary>
162
+ /// Merges two heterogeneous sequences ordered by a common key type
163
+ /// into a homogeneous one. Additional parameters specify the
164
+ /// element key by which the sequences are ordered, the result when
165
+ /// element is found in first sequence but not in the second,
166
+ /// the result when element is found in second sequence but not in
167
+ /// the first, the result when elements are found in both sequences
168
+ /// and a method for comparing keys.
169
+ /// </summary>
170
+ /// <remarks>
171
+ /// This method uses deferred execution. The behavior is undefined
172
+ /// if the sequences are unordered (by key) as inputs.
173
+ /// </remarks>
174
+
175
+ public static IEnumerable < TResult > OrderedMerge < TFirst , TSecond , TKey , TResult > (
176
+ this IEnumerable < TFirst > first ,
177
+ IEnumerable < TSecond > second ,
178
+ Func < TFirst , TKey > firstKeySelector ,
179
+ Func < TSecond , TKey > secondKeySelector ,
180
+ Func < TFirst , TResult > firstSelector ,
181
+ Func < TSecond , TResult > secondSelector ,
182
+ Func < TFirst , TSecond , TResult > bothSelector ,
183
+ IComparer < TKey > comparer )
184
+ {
185
+ if ( first == null ) throw new ArgumentNullException ( "first" ) ;
186
+ if ( second == null ) throw new ArgumentNullException ( "second" ) ;
187
+ if ( firstKeySelector == null ) throw new ArgumentNullException ( "firstKeySelector" ) ;
188
+ if ( secondKeySelector == null ) throw new ArgumentNullException ( "secondKeySelector" ) ;
189
+ if ( firstSelector == null ) throw new ArgumentNullException ( "firstSelector" ) ;
190
+ if ( bothSelector == null ) throw new ArgumentNullException ( "bothSelector" ) ;
191
+ if ( secondSelector == null ) throw new ArgumentNullException ( "secondSelector" ) ;
192
+
193
+ return OrderedMergeImpl ( first , second ,
194
+ firstKeySelector , secondKeySelector ,
195
+ firstSelector , secondSelector , bothSelector ,
196
+ comparer ?? Comparer < TKey > . Default ) ;
197
+ }
198
+
199
+ static IEnumerable < TResult > OrderedMergeImpl < TFirst , TSecond , TKey , TResult > (
200
+ IEnumerable < TFirst > first ,
201
+ IEnumerable < TSecond > second ,
202
+ Func < TFirst , TKey > firstKeySelector ,
203
+ Func < TSecond , TKey > secondKeySelector ,
204
+ Func < TFirst , TResult > firstSelector ,
205
+ Func < TSecond , TResult > secondSelector ,
206
+ Func < TFirst , TSecond , TResult > bothSelector ,
207
+ IComparer < TKey > comparer )
208
+ {
209
+ Debug . Assert ( first != null ) ;
210
+ Debug . Assert ( second != null ) ;
211
+ Debug . Assert ( firstKeySelector != null ) ;
212
+ Debug . Assert ( secondKeySelector != null ) ;
213
+ Debug . Assert ( firstSelector != null ) ;
214
+ Debug . Assert ( secondSelector != null ) ;
215
+ Debug . Assert ( bothSelector != null ) ;
216
+ Debug . Assert ( comparer != null ) ;
217
+
218
+ using ( var e1 = first . GetEnumerator ( ) )
219
+ using ( var e2 = second . GetEnumerator ( ) )
220
+ {
221
+ var gotFirst = e1 . MoveNext ( ) ;
222
+ var gotSecond = e2 . MoveNext ( ) ;
223
+
224
+ while ( gotFirst || gotSecond )
225
+ {
226
+ if ( gotFirst && gotSecond )
227
+ {
228
+ var element1 = e1 . Current ;
229
+ var key1 = firstKeySelector ( element1 ) ;
230
+ var element2 = e2 . Current ;
231
+ var key2 = secondKeySelector ( element2 ) ;
232
+ var comparison = comparer . Compare ( key1 , key2 ) ;
233
+
234
+ if ( comparison < 0 )
235
+ {
236
+ yield return firstSelector ( element1 ) ;
237
+ gotFirst = e1 . MoveNext ( ) ;
238
+ }
239
+ else if ( comparison > 0 )
240
+ {
241
+ yield return secondSelector ( element2 ) ;
242
+ gotSecond = e2 . MoveNext ( ) ;
243
+ }
244
+ else
245
+ {
246
+ yield return bothSelector ( element1 , element2 ) ;
247
+ gotFirst = e1 . MoveNext ( ) ;
248
+ gotSecond = e2 . MoveNext ( ) ;
249
+ }
250
+ }
251
+ else if ( gotSecond )
252
+ {
253
+ yield return secondSelector ( e2 . Current ) ;
254
+ gotSecond = e2 . MoveNext ( ) ;
255
+ }
256
+ else // (gotFirst)
257
+ {
258
+ yield return firstSelector ( e1 . Current ) ;
259
+ gotFirst = e1 . MoveNext ( ) ;
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
0 commit comments