@@ -9,7 +9,7 @@ namespace Open.Collections
99{
1010 public static partial class Extensions
1111 {
12- static IEnumerable < T [ ] > CombinationsCore < T > ( IReadOnlyList < T > source , int length , bool distinctSet , T [ ] ? buffer = null )
12+ static IEnumerable < T [ ] > CombinationsCore < T > ( IReadOnlyList < T > source , int length , bool distinctSet , T [ ] buffer )
1313 {
1414 Debug . Assert ( length != 0 ) ;
1515 var count = source . Count ;
@@ -59,12 +59,11 @@ bool GetNext()
5959
6060 while ( GetNext ( ) )
6161 {
62- var result = buffer ?? new T [ length ] ;
6362 for ( var i = 0 ; i < length ; i ++ )
6463 {
65- result [ i ] = source [ indexes [ i ] ] ;
64+ buffer ! [ i ] = source [ indexes [ i ] ] ;
6665 }
67- yield return result ;
66+ yield return buffer ! ;
6867 }
6968 }
7069 finally
@@ -73,17 +72,25 @@ bool GetNext()
7372 }
7473 }
7574
76- /// <summary>
77- /// Enumerates all possible combinations of values.
78- /// Results can be different permutations of another set.
79- ///
80- /// Example:
81- /// [0, 0], [0, 1], [1, 0], [1, 1] where [0, 1] and [1, 0] are a different permutatation of the same set.
82- /// </summary>
83- /// <param name="elements">The elements to draw from.</param>
84- /// <param name="length">The length of each result.</param>
85- /// <param name="buffer">An optional buffer that is filled with the values and returned as the yielded value instead of a new array</param>
86- public static IEnumerable < T [ ] > Combinations < T > ( this IEnumerable < T > elements , int length , T [ ] ? buffer = null )
75+ static IEnumerable < T [ ] > CombinationsCore < T > ( IReadOnlyList < T > source , int length , bool distinctSet )
76+ {
77+ var pool = ArrayPool < T > . Shared ;
78+ var buffer = pool . Rent ( length ) ;
79+ try
80+ {
81+ foreach ( var b in CombinationsCore ( source , length , distinctSet , buffer ) )
82+ yield return b ;
83+ }
84+ finally
85+ {
86+ pool . Return ( buffer , true ) ;
87+ }
88+ }
89+
90+
91+ /// <inheritdoc cref="Combinations{T}(IEnumerable{T}, int)"/>
92+ /// <param name="buffer">A buffer that is filled with the values and returned as the yielded value instead of a new array.</param>
93+ public static IEnumerable < T [ ] > Combinations < T > ( this IEnumerable < T > elements , int length , T [ ] buffer )
8794 {
8895 if ( elements is null )
8996 throw new ArgumentNullException ( nameof ( elements ) ) ;
@@ -96,17 +103,10 @@ public static IEnumerable<T[]> Combinations<T>(this IEnumerable<T> elements, int
96103 return source . Count == 0 ? Enumerable . Empty < T [ ] > ( ) : CombinationsCore ( source , length , false , buffer ) ;
97104 }
98105
99- /// <summary>
100- /// Enumerates all possible distinct set combinations.
101- /// A set that has its items reordered is not distinct from the original.
102- ///
103- /// Example:
104- /// [0, 0], [0, 1], [1, 1] where [1, 0] is not included as it is not a disticnt set from [0, 1].
105- /// </summary>
106- /// <param name="elements">The elements to draw from.</param>
107- /// <param name="length">The length of each result.</param>
106+
107+ /// <inheritdoc cref="CombinationsDistinct{T}(IEnumerable{T}, int)"/>
108108 /// <param name="buffer">An optional buffer that is filled with the values and returned as the yielded value instead of a new array</param>
109- public static IEnumerable < T [ ] > CombinationsDistinct < T > ( this IEnumerable < T > elements , int length , T [ ] ? buffer = null )
109+ public static IEnumerable < T [ ] > CombinationsDistinct < T > ( this IEnumerable < T > elements , int length , T [ ] buffer )
110110 {
111111 if ( elements is null )
112112 throw new ArgumentNullException ( nameof ( elements ) ) ;
@@ -133,69 +133,105 @@ public static IEnumerable<T[]> Combinations<T>(this IEnumerable<T> elements, int
133133 var count = source . Count ;
134134 if ( count == 0 ) return Enumerable . Empty < T [ ] > ( ) ;
135135
136- return uniqueOnly ? source . Subsets ( length ) : CombinationsCore ( source , length , true ) ;
136+ if ( uniqueOnly ) return source . Subsets ( length ) ;
137+ return uniqueOnly ? source . Subsets ( length ) : CombinationsCore ( source , length , true ) . Select ( e=> e . AsCopy ( length ) ) ;
137138 }
138139
139- /// <summary>
140- /// Enumerates all possible (order retained) combinations of the source elements up to the length.
141- /// </summary>
142- /// <param name="elements">The elements to draw from.</param>
143- /// <param name="length">The length of each result.</param>
144- public static IEnumerable < T [ ] > CombinationsBuffered < T > ( this IEnumerable < T > elements , int length )
140+ /// <inheritdoc cref="Combinations{T}(IEnumerable{T}, int)"/>
141+ /// <remarks>Values are yielded as read only memory buffer that should not be retained as its array is returned to pool afterwards.</remarks>
142+ /// <returns>An enumerable the yields as read only memory buffer that should not be retained as its array is returned to pool afterwards.</returns>
143+ public static IEnumerable < ReadOnlyMemory < T > > CombinationsBuffered < T > ( this IEnumerable < T > elements , int length )
145144 {
146145 if ( elements is null )
147146 throw new ArgumentNullException ( nameof ( elements ) ) ;
148147 if ( length < 0 )
149148 throw new ArgumentOutOfRangeException ( nameof ( length ) , length , "Cannot be less than zero." ) ;
150149 Contract . EndContractBlock ( ) ;
151150
152- if ( length == 0 )
151+ if ( length == 0 ) yield break ;
152+
153+ var pool = ArrayPool < T > . Shared ;
154+ var buffer = pool . Rent ( length ) ;
155+ var readBuffer = new ReadOnlyMemory < T > ( buffer , 0 , length ) ;
156+ try
157+ {
158+ foreach ( var _ in Combinations ( elements , length , buffer ) )
159+ yield return readBuffer ;
160+ }
161+ finally
153162 {
154- yield break ;
163+ pool . Return ( buffer , true ) ;
155164 }
165+ }
166+
167+
168+ /// <inheritdoc cref="CombinationsDistinct{T}(IEnumerable{T}, int)"/>
169+ /// <remarks>Values are yielded as read only memory buffer that should not be retained as its array is returned to pool afterwards.</remarks>
170+ /// <returns>An enumerable the yields as read only memory buffer that should not be retained as its array is returned to pool afterwards.</returns>
171+ public static IEnumerable < ReadOnlyMemory < T > > CombinationsDistinctBuffered < T > ( this IEnumerable < T > elements , int length )
172+ {
173+ if ( elements is null )
174+ throw new ArgumentNullException ( nameof ( elements ) ) ;
175+ if ( length < 0 )
176+ throw new ArgumentOutOfRangeException ( nameof ( length ) , length , "Cannot be less than zero." ) ;
177+ Contract . EndContractBlock ( ) ;
178+
179+ if ( length == 0 ) yield break ;
156180
157181 var pool = ArrayPool < T > . Shared ;
158182 var buffer = pool . Rent ( length ) ;
183+ var readBuffer = new ReadOnlyMemory < T > ( buffer , 0 , length ) ;
159184 try
160185 {
161- foreach ( var c in Combinations ( elements , length , buffer ) )
162- yield return c ;
186+ foreach ( var _ in CombinationsDistinct ( elements , length , buffer ) )
187+ yield return readBuffer ;
163188 }
164189 finally
165190 {
166191 pool . Return ( buffer , true ) ;
167192 }
168193 }
169194
195+ /// <inheritdoc cref="Combinations{T}(IEnumerable{T})"/>
196+ /// <param name="length">The length of each result.</param>
197+ public static IEnumerable < T [ ] > Combinations < T > ( this IEnumerable < T > elements , int length )
198+ {
199+ foreach ( var c in CombinationsBuffered ( elements , length ) )
200+ yield return c . ToArray ( ) ;
201+ }
202+
203+ /// <inheritdoc cref="CombinationsDistinct{T}(IEnumerable{T})"/>
204+ /// <param name="length">The length of each result.</param>
205+ public static IEnumerable < T [ ] > CombinationsDistinct < T > ( this IEnumerable < T > elements , int length )
206+ {
207+ foreach ( var c in CombinationsDistinctBuffered ( elements , length ) )
208+ yield return c . ToArray ( ) ;
209+ }
210+
170211
171212 /// <summary>
172213 /// Enumerates all possible combinations of values.
173214 /// Results can be different permutations of another set.
174- /// Examples:
175- /// [0, 0], [0, 1], [1, 0], [1, 1] where [0, 1] and [1, 0] are a different permutatation of the same set.
176215 /// </summary>
177- /// <param name="elements">The elements to draw from.</param>\
216+ /// <example>[0, 0], [0, 1], [1, 0], [1, 1] where [0, 1] and [1, 0] are a different permutatation of the same set.</example>
217+ /// <param name="elements">The elements to draw from.</param>
178218 public static IEnumerable < T [ ] > Combinations < T > ( this IEnumerable < T > elements )
179219 {
180- if ( elements is null )
181- throw new ArgumentNullException ( nameof ( elements ) ) ;
220+ if ( elements is null ) throw new ArgumentNullException ( nameof ( elements ) ) ;
182221 Contract . EndContractBlock ( ) ;
183222 var source = elements as IReadOnlyList < T > ?? elements . ToArray ( ) ;
184223 return source . Count == 0 ? Enumerable . Empty < T [ ] > ( ) : Combinations ( source , source . Count ) ;
185224 }
186225
187226 /// <summary>
188227 /// Enumerates all possible distinct set combinations.
189- /// A set that has its items reordered is not distinct from the original.
190- /// Examples:
191- /// [0, 0], [0, 1], [1, 1] where [1, 0] is not included as it is not a disticnt set from [0, 1].
192- ///
228+ /// In contrast a set that has its items reordered is not distinct from the original.
193229 /// </summary>
230+ /// <example>[0, 0], [0, 1], [1, 1] where [1, 0] is not included as it is not a disticnt set from [0, 1].</example>
194231 /// <param name="elements">The elements to draw from.</param>
195232 public static IEnumerable < T [ ] > CombinationsDistinct < T > ( this IEnumerable < T > elements )
196233 {
197- if ( elements is null )
198- throw new ArgumentNullException ( nameof ( elements ) ) ;
234+ if ( elements is null ) throw new ArgumentNullException ( nameof ( elements ) ) ;
199235 Contract . EndContractBlock ( ) ;
200236 var source = elements as IReadOnlyList < T > ?? elements . ToArray ( ) ;
201237 return source . Count == 0 ? Enumerable . Empty < T [ ] > ( ) : CombinationsDistinct ( source , source . Count ) ;
0 commit comments