@@ -12,10 +12,11 @@ public static partial class SuperEnumerable
12
12
/// <param name="count">Number of (maximum) elements to return.</param>
13
13
/// <returns>A sequence containing at most top <paramref name="count"/>
14
14
/// elements from source, in their ascending order.</returns>
15
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
16
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
15
17
/// <remarks>
16
18
/// This operator uses deferred execution and streams it results.
17
19
/// </remarks>
18
-
19
20
public static IEnumerable < T > PartialSort < T > ( this IEnumerable < T > source , int count )
20
21
{
21
22
return source . PartialSort ( count , comparer : null ) ;
@@ -33,10 +34,11 @@ public static IEnumerable<T> PartialSort<T>(this IEnumerable<T> source, int coun
33
34
/// <param name="direction">The direction in which to sort the elements</param>
34
35
/// <returns>A sequence containing at most top <paramref name="count"/>
35
36
/// elements from source, in the specified order.</returns>
37
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
38
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
36
39
/// <remarks>
37
40
/// This operator uses deferred execution and streams it results.
38
41
/// </remarks>
39
-
40
42
public static IEnumerable < T > PartialSort < T > (
41
43
this IEnumerable < T > source , int count , OrderByDirection direction )
42
44
{
@@ -55,10 +57,11 @@ public static IEnumerable<T> PartialSort<T>(
55
57
/// <param name="comparer">A <see cref="IComparer{T}"/> to compare elements.</param>
56
58
/// <returns>A sequence containing at most top <paramref name="count"/>
57
59
/// elements from source, in their ascending order.</returns>
60
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
61
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
58
62
/// <remarks>
59
63
/// This operator uses deferred execution and streams it results.
60
64
/// </remarks>
61
-
62
65
public static IEnumerable < T > PartialSort < T > (
63
66
this IEnumerable < T > source ,
64
67
int count , IComparer < T > ? comparer )
@@ -80,19 +83,52 @@ public static IEnumerable<T> PartialSort<T>(
80
83
/// <param name="direction">The direction in which to sort the elements</param>
81
84
/// <returns>A sequence containing at most top <paramref name="count"/>
82
85
/// elements from source, in the specified order.</returns>
86
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
87
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
83
88
/// <remarks>
84
89
/// This operator uses deferred execution and streams it results.
85
90
/// </remarks>
86
-
87
91
public static IEnumerable < T > PartialSort < T > (
88
92
this IEnumerable < T > source , int count ,
89
93
IComparer < T > ? comparer , OrderByDirection direction )
90
94
{
91
95
source . ThrowIfNull ( ) ;
96
+ count . ThrowIfLessThan ( 1 ) ;
97
+
92
98
comparer ??= Comparer < T > . Default ;
93
99
if ( direction == OrderByDirection . Descending )
94
100
comparer = new ReverseComparer < T > ( comparer ) ;
95
- return PartialSortByImpl < T , T > ( source , count , keySelector : null , keyComparer : null , comparer ) ;
101
+
102
+ return _ ( source , count , comparer ) ;
103
+
104
+ static IEnumerable < T > _ ( IEnumerable < T > source , int count , IComparer < T > comparer )
105
+ {
106
+ var top = new SortedSet < ( T item , int index ) > (
107
+ Comparer < ( T item , int index ) > . Create ( ( x , y ) =>
108
+ {
109
+ var result = comparer . Compare ( x . item , y . item ) ;
110
+ return result != 0 ? result :
111
+ Comparer < long > . Default . Compare ( x . index , y . index ) ;
112
+ } ) ) ;
113
+
114
+ foreach ( var ( index , item ) in source . Index ( ) )
115
+ {
116
+ if ( top . Count < count )
117
+ {
118
+ top . Add ( ( item , index ) ) ;
119
+ continue ;
120
+ }
121
+
122
+ if ( comparer . Compare ( item , top . Max . item ) >= 0 )
123
+ continue ;
124
+
125
+ top . Remove ( top . Max ) ;
126
+ top . Add ( ( item , index ) ) ;
127
+ }
128
+
129
+ foreach ( var ( item , _) in top )
130
+ yield return item ;
131
+ }
96
132
}
97
133
98
134
/// <summary>
@@ -106,10 +142,12 @@ public static IEnumerable<T> PartialSort<T>(
106
142
/// <param name="count">Number of (maximum) elements to return.</param>
107
143
/// <returns>A sequence containing at most top <paramref name="count"/>
108
144
/// elements from source, in ascending order of their keys.</returns>
145
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
146
+ /// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is <see langword="null"/>.</exception>
147
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
109
148
/// <remarks>
110
149
/// This operator uses deferred execution and streams it results.
111
150
/// </remarks>
112
-
113
151
public static IEnumerable < TSource > PartialSortBy < TSource , TKey > (
114
152
this IEnumerable < TSource > source , int count ,
115
153
Func < TSource , TKey > keySelector )
@@ -130,10 +168,12 @@ public static IEnumerable<TSource> PartialSortBy<TSource, TKey>(
130
168
/// <param name="direction">The direction in which to sort the elements</param>
131
169
/// <returns>A sequence containing at most top <paramref name="count"/>
132
170
/// elements from source, in the specified order of their keys.</returns>
171
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
172
+ /// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is <see langword="null"/>.</exception>
173
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
133
174
/// <remarks>
134
175
/// This operator uses deferred execution and streams it results.
135
176
/// </remarks>
136
-
137
177
public static IEnumerable < TSource > PartialSortBy < TSource , TKey > (
138
178
this IEnumerable < TSource > source , int count ,
139
179
Func < TSource , TKey > keySelector , OrderByDirection direction )
@@ -154,10 +194,12 @@ public static IEnumerable<TSource> PartialSortBy<TSource, TKey>(
154
194
/// <param name="comparer">A <see cref="IComparer{T}"/> to compare elements.</param>
155
195
/// <returns>A sequence containing at most top <paramref name="count"/>
156
196
/// elements from source, in ascending order of their keys.</returns>
197
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
198
+ /// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is <see langword="null"/>.</exception>
199
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
157
200
/// <remarks>
158
201
/// This operator uses deferred execution and streams it results.
159
202
/// </remarks>
160
-
161
203
public static IEnumerable < TSource > PartialSortBy < TSource , TKey > (
162
204
this IEnumerable < TSource > source , int count ,
163
205
Func < TSource , TKey > keySelector ,
@@ -181,87 +223,60 @@ public static IEnumerable<TSource> PartialSortBy<TSource, TKey>(
181
223
/// <param name="direction">The direction in which to sort the elements</param>
182
224
/// <returns>A sequence containing at most top <paramref name="count"/>
183
225
/// elements from source, in the specified order of their keys.</returns>
226
+ /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
227
+ /// <exception cref="ArgumentNullException"><paramref name="keySelector"/> is <see langword="null"/>.</exception>
228
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is less than 1.</exception>
184
229
/// <remarks>
185
230
/// This operator uses deferred execution and streams it results.
186
231
/// </remarks>
187
-
188
232
public static IEnumerable < TSource > PartialSortBy < TSource , TKey > (
189
233
this IEnumerable < TSource > source , int count ,
190
234
Func < TSource , TKey > keySelector ,
191
235
IComparer < TKey > ? comparer ,
192
236
OrderByDirection direction )
193
237
{
194
238
source . ThrowIfNull ( ) ;
239
+ count . ThrowIfLessThan ( 1 ) ;
195
240
keySelector . ThrowIfNull ( ) ;
196
241
197
242
comparer ??= Comparer < TKey > . Default ;
198
243
if ( direction == OrderByDirection . Descending )
199
244
comparer = new ReverseComparer < TKey > ( comparer ) ;
200
- return PartialSortByImpl ( source , count , keySelector , keyComparer : comparer , comparer : null ) ;
201
- }
202
245
203
- static IEnumerable < TSource > PartialSortByImpl < TSource , TKey > (
204
- IEnumerable < TSource > source , int count ,
205
- Func < TSource , TKey > ? keySelector ,
206
- IComparer < TKey > ? keyComparer ,
207
- IComparer < TSource > ? comparer )
208
- {
209
- var top = new List < TSource > ( count ) ;
246
+ return _ ( source , count , keySelector , comparer ) ;
210
247
211
- static int ? Insert < T > ( List < T > list , T item , IComparer < T > comparer , int count )
248
+ static IEnumerable < TSource > _ ( IEnumerable < TSource > source , int count , Func < TSource , TKey > keySelector , IComparer < TKey > comparer )
212
249
{
213
- var i = list . BinarySearch ( item , comparer ) ;
214
- // find the place to insert
215
- if ( i < 0 && ( i = ~ i ) >= count )
216
- return null ;
217
- // move forward until we get to next larger
218
- while ( i < list . Count && comparer . Compare ( item , list [ i ] ) == 0 )
219
- i ++ ;
220
- // is the list full?
221
- if ( list . Count == count )
222
- {
223
- // if our insert location is at the end of the list
224
- if ( i == list . Count
225
- // and we're _not larger_ than the last item
226
- && comparer . Compare ( item , list [ ^ 1 ] ) <= 0 )
250
+ var top = new SortedSet < ( TKey Item , int Index ) > (
251
+ Comparer < ( TKey item , int index ) > . Create ( ( x , y ) =>
227
252
{
228
- // then don't affect the list
229
- return null ;
230
- }
231
- // remove last item
232
- list . RemoveAt ( count - 1 ) ;
233
- }
253
+ var result = comparer . Compare ( x . item , y . item ) ;
254
+ return result != 0 ? result :
255
+ Comparer < long > . Default . Compare ( x . index , y . index ) ;
256
+ } ) ) ;
257
+ var dic = new Dictionary < ( TKey Item , int Index ) , TSource > ( count ) ;
234
258
235
- list . Insert ( i , item ) ;
236
- return i ;
237
- }
238
-
239
- if ( keyComparer != null )
240
- {
241
- var keys = new List < TKey > ( count ) ;
242
-
243
- foreach ( var item in source )
259
+ foreach ( var ( index , item ) in source . Index ( ) )
244
260
{
245
- var key = keySelector ! ( item ) ;
246
- if ( Insert ( keys , key , keyComparer , count ) is { } i )
261
+ var key = ( key : keySelector ( item ) , index ) ;
262
+ if ( top . Count < count )
247
263
{
248
- if ( top . Count == count )
249
- top . RemoveAt ( count - 1 ) ;
250
- top . Insert ( i , item ) ;
264
+ top . Add ( key ) ;
265
+ dic [ key ] = item ;
266
+ continue ;
251
267
}
268
+
269
+ if ( comparer . Compare ( key . key , top . Max . Item ) >= 0 )
270
+ continue ;
271
+
272
+ dic . Remove ( top . Max ) ;
273
+ top . Remove ( top . Max ) ;
274
+ top . Add ( key ) ;
275
+ dic [ key ] = item ;
252
276
}
253
- }
254
- else if ( comparer != null )
255
- {
256
- foreach ( var item in source )
257
- _ = Insert ( top , item , comparer , count ) ;
258
- }
259
- else
260
- {
261
- throw new NotSupportedException ( "Should not be able to reach here." ) ;
262
- }
263
277
264
- foreach ( var item in top )
265
- yield return item ;
278
+ foreach ( var entry in top )
279
+ yield return dic [ entry ] ;
280
+ }
266
281
}
267
282
}
0 commit comments