@@ -34,38 +34,31 @@ public static partial class MoreEnumerable
34
34
/// <param name="size">The size (number of elements) in each window</param>
35
35
/// <returns>A series of sequences representing each sliding window subsequence</returns>
36
36
37
- public static IEnumerable < IList < TSource > > Window < TSource > ( this IEnumerable < TSource > source , int size )
37
+ public static IEnumerable < IReadOnlyList < TSource > > Window < TSource > ( this IEnumerable < TSource > source , int size )
38
38
{
39
39
if ( source == null ) throw new ArgumentNullException ( nameof ( source ) ) ;
40
- if ( size <= 0 ) throw new ArgumentOutOfRangeException ( nameof ( size ) ) ;
40
+ if ( size < 0 ) throw new ArgumentOutOfRangeException ( nameof ( size ) ) ;
41
41
42
- return _ ( ) ; IEnumerable < IList < TSource > > _ ( )
42
+ return _ ( ) ; IEnumerable < IReadOnlyList < TSource > > _ ( )
43
43
{
44
- using var iter = source . GetEnumerator ( ) ;
44
+ var cache = new List < TSource > ( ) ;
45
45
46
- // generate the first window of items
47
- var window = new TSource [ size ] ;
48
- int i ;
49
- for ( i = 0 ; i < size && iter . MoveNext ( ) ; i ++ )
50
- window [ i ] = iter . Current ;
46
+ using var enumerator = source . GetEnumerator ( ) ;
51
47
52
- if ( i < size )
53
- yield break ;
48
+ var hasNext = true ;
49
+ bool MoveNext ( ) => hasNext && ( hasNext = enumerator . MoveNext ( ) ) ;
54
50
55
- // return the first window (whatever size it may be)
56
- yield return window ;
51
+ for ( var i = 0 ; i < size - 1 && MoveNext ( ) ; i ++ )
52
+ {
53
+ cache . Add ( enumerator . Current ) ;
54
+ }
57
55
58
- // generate the next window by shifting forward by one item
59
- while ( iter . MoveNext ( ) )
56
+ var offset = 0 ;
57
+ while ( MoveNext ( ) )
60
58
{
61
- // NOTE: If we used a circular queue rather than a list,
62
- // we could make this quite a bit more efficient.
63
- // Sadly the BCL does not offer such a collection.
64
- var newWindow = new TSource [ size ] ;
65
- Array . Copy ( window , 1 , newWindow , 0 , size - 1 ) ;
66
- newWindow [ size - 1 ] = iter . Current ;
67
- yield return newWindow ;
68
- window = newWindow ;
59
+ cache . Add ( enumerator . Current ) ;
60
+ yield return new WindowedList < TSource > ( cache , offset , cache . Count - offset ) ;
61
+ offset ++ ;
69
62
}
70
63
}
71
64
}
0 commit comments