1- namespace SuperLinq ;
1+ namespace SuperLinq ;
22
33public static partial class SuperEnumerable
44{
@@ -35,43 +35,98 @@ public static IEnumerable<T> Exclude<T>(this IEnumerable<T> sequence, int startI
3535 ArgumentOutOfRangeException . ThrowIfNegative ( startIndex ) ;
3636 ArgumentOutOfRangeException . ThrowIfNegative ( count ) ;
3737
38- if ( count == 0 )
39- return sequence ;
40-
41- return sequence switch
38+ return ( count , sequence ) switch
4239 {
43- IList < T > list => new ExcludeListIterator < T > ( list , startIndex , count ) ,
44- ICollection < T > collection => new ExcludeCollectionIterator < T > ( collection , startIndex , count ) ,
40+ ( 0 , _ ) => sequence ,
41+ ( _, IList < T > list ) => new ExcludeListIterator < T > ( list , startIndex , count ) ,
42+ ( _, ICollection < T > collection ) => new ExcludeCollectionIterator < T > ( collection , startIndex , count ) ,
4543 _ => ExcludeCore ( sequence , startIndex , count )
4644 } ;
4745 }
4846
49- private sealed class ExcludeCollectionIterator < T > (
50- ICollection < T > source ,
51- int startIndex ,
52- int count
53- ) : CollectionIterator < T >
47+ /// <summary>
48+ /// Excludes a contiguous number of elements from a sequence starting at a given index.
49+ /// </summary>
50+ /// <typeparam name="T">
51+ /// The type of the elements of the sequence
52+ /// </typeparam>
53+ /// <param name="sequence">
54+ /// The sequence to exclude elements from
55+ /// </param>
56+ /// <param name="range">
57+ /// The zero-based index at which to begin excluding elements
58+ /// </param>
59+ /// <returns>
60+ /// A sequence that excludes the specified portion of elements
61+ /// </returns>
62+ /// <exception cref="ArgumentNullException">
63+ /// <paramref name="sequence"/> is <see langword="null" />.
64+ /// </exception>
65+ /// <exception cref="ArgumentOutOfRangeException">
66+ /// <paramref name="range.Start.Value"/> or <paramref name="range.End.Value"/> is less than <c>0</c>.
67+ /// </exception>
68+ /// <remarks>
69+ /// This method uses deferred execution and streams its results.
70+ /// </remarks>
71+ public static IEnumerable < T > Exclude < T > ( this IEnumerable < T > sequence , Range range )
72+ {
73+ ArgumentNullException . ThrowIfNull ( sequence ) ;
74+
75+ var startFromEnd = range . Start . IsFromEnd ;
76+ var endFromEnd = range . End . IsFromEnd ;
77+ if ( ( startFromEnd , endFromEnd ) == ( false , false ) )
78+ {
79+ return Exclude ( sequence , range . Start . Value , range . End . Value - range . Start . Value ) ;
80+ }
81+
82+ if ( sequence . TryGetCollectionCount ( ) is int count )
83+ {
84+ var ( start , length ) = range . GetOffsetAndLength ( count ) ;
85+ return Exclude ( sequence , start , length ) ;
86+ }
87+
88+ return ( startFromEnd , endFromEnd ) switch
89+ {
90+ ( false , true ) => ExcludeEndFromEnd ( sequence , range ) ,
91+ ( true , false ) => ExcludeStartFromEnd ( sequence , range ) ,
92+ ( true , true ) when range . Start . Value < range . End . Value =>
93+ ThrowHelper . ThrowArgumentOutOfRangeException < IEnumerable < T > > ( "length" ) ,
94+ _ => ExcludeRange ( sequence , range ) ,
95+ } ;
96+ }
97+
98+ /// <summary>
99+ /// Represents an iterator for excluding elements from a collection.
100+ /// </summary>
101+ /// <typeparam name="T">Specifies the type of elements in the collection.</typeparam>
102+ private sealed class ExcludeCollectionIterator < T > ( ICollection < T > source , int startIndex , int count )
103+ : CollectionIterator < T >
54104 {
105+ /// <summary>
106+ /// Gets the number of elements in the source collection after excluding the specified portion of elements.
107+ /// </summary>
55108 public override int Count =>
56109 source . Count < startIndex ? source . Count :
57110 source . Count < startIndex + count ? startIndex :
58111 source . Count - count ;
59112
113+ /// <inheritdoc cref="IEnumerable{T}" />
60114 protected override IEnumerable < T > GetEnumerable ( ) =>
61115 ExcludeCore ( source , startIndex , count ) ;
62116 }
63117
64- private sealed class ExcludeListIterator < T > (
65- IList < T > source ,
66- int startIndex ,
67- int count
68- ) : ListIterator < T >
118+ private sealed class ExcludeListIterator < T > ( IList < T > source , int startIndex , int count )
119+ : ListIterator < T >
69120 {
121+ /// <summary>
122+ /// Gets the number of elements in the source collection after excluding the specified portion of elements.
123+ /// </summary>
70124 public override int Count =>
71125 source . Count < startIndex ? source . Count :
72126 source . Count < startIndex + count ? startIndex :
73127 source . Count - count ;
74128
129+ /// <inheritdoc cref="IEnumerable{T}" />
75130 protected override IEnumerable < T > GetEnumerable ( )
76131 {
77132 var cnt = ( uint ) source . Count ;
@@ -82,6 +137,7 @@ protected override IEnumerable<T> GetEnumerable()
82137 yield return source [ i ] ;
83138 }
84139
140+ /// <inheritdoc cref="IEnumerable{T}"/>
85141 protected override T ElementAt ( int index )
86142 {
87143 ArgumentOutOfRangeException . ThrowIfNegative ( index ) ;
@@ -102,7 +158,81 @@ private static IEnumerable<T> ExcludeCore<T>(IEnumerable<T> sequence, int startI
102158 {
103159 if ( index < startIndex || index >= endIndex )
104160 yield return item ;
161+
105162 index ++ ;
106163 }
107164 }
165+
166+ private static IEnumerable < T > ExcludeRange < T > ( IEnumerable < T > sequence , Range range )
167+ {
168+ var start = range . Start . Value ;
169+ var queue = new Queue < T > ( start + 1 ) ;
170+ foreach ( var e in sequence )
171+ {
172+ queue . Enqueue ( e ) ;
173+ if ( queue . Count > start )
174+ yield return queue . Dequeue ( ) ;
175+ }
176+
177+ start = Math . Min ( start , queue . Count ) ;
178+ var length = start - range . End . Value ;
179+ while ( length > 0 )
180+ {
181+ if ( ! queue . TryDequeue ( out var _ ) )
182+ yield break ;
183+ length -- ;
184+ }
185+
186+ while ( queue . TryDequeue ( out var element ) )
187+ yield return element ;
188+ }
189+
190+ private static IEnumerable < T > ExcludeStartFromEnd < T > ( IEnumerable < T > sequence , Range range )
191+ {
192+ var count = 0 ;
193+ var start = range . Start . Value ;
194+ var queue = new Queue < T > ( start + 1 ) ;
195+ foreach ( var e in sequence )
196+ {
197+ count ++ ;
198+ queue . Enqueue ( e ) ;
199+ if ( queue . Count > start )
200+ yield return queue . Dequeue ( ) ;
201+ }
202+
203+ start = Math . Max ( range . Start . GetOffset ( count ) , 0 ) ;
204+ var length = range . End . Value - start ;
205+
206+ while ( length > 0 )
207+ {
208+ if ( ! queue . TryDequeue ( out var _ ) )
209+ yield break ;
210+ length -- ;
211+ }
212+
213+ while ( queue . TryDequeue ( out var element ) )
214+ yield return element ;
215+ }
216+
217+ private static IEnumerable < T > ExcludeEndFromEnd < T > ( IEnumerable < T > sequence , Range range )
218+ {
219+ var count = 0 ;
220+ var start = range . Start . Value ;
221+ var end = range . End . Value ;
222+ var queue = new Queue < T > ( end + 1 ) ;
223+ foreach ( var e in sequence )
224+ {
225+ count ++ ;
226+ queue . Enqueue ( e ) ;
227+ if ( queue . Count > end )
228+ {
229+ var el = queue . Dequeue ( ) ;
230+ if ( ( count - end ) <= start )
231+ yield return el ;
232+ }
233+ }
234+
235+ while ( queue . TryDequeue ( out var element ) )
236+ yield return element ;
237+ }
108238}
0 commit comments