IEnumerableExtensions Class
Definition
Provides deferred-execution combinators over IEnumerable<T> - batching, caching, multi-aggregate fan-out, recursive descent, randomization, and set-membership predicates - that complement the standard LINQ surface for production pipeline code.
public static class IEnumerableExtensions
- Inheritance
-
IEnumerableExtensions
- Inherited Members
Remarks
LINQ-to-Objects covers the common cases - Where, Select, GroupBy, Aggregate - but most
non-trivial pipelines end up reaching for the same hand-rolled helpers: chunking a stream into fixed-size windows,
materializing once and replaying many times, walking a tree of children without recursion, or computing several
aggregates in a single pass to avoid re-enumerating an expensive source. This class collects those helpers behind
verb-led names and shapes them so that they compose naturally with the rest of LINQ.
The API surface clusters into: chunking and pooling (Batch, BatchPooled), replay support (Cache
), set-membership predicates (ContainsAll, ContainsAny), tree traversal (RecursiveSelect),
shuffling (Randomize), and multi-aggregate fan-out (Aggregate overloads that compute up to several
seeds in a single enumeration). Each method is offered with the overload set required to keep the call site clean -
a default form, a form that accepts a projection or comparer, and where useful a form that hands the caller a pooled
buffer to drive throughput-sensitive work.
Where the contract is naturally lazy the implementation defers all work until enumeration begins; where it is
naturally eager (the Aggregate, ContainsAll, and ContainsAny families) the source is enumerated
exactly once. Argument validation runs eagerly via ThrowHelper, so callers see
ArgumentNullException at the call site rather than mid-iteration. Methods that accept an
IEqualityComparer<T> default to Default when one is not supplied.
IEnumerable<int> source = Enumerable.Range(1, 9);
// Chunk into windows of three, projecting each element.
foreach (var window in source.Batch(3, static x => x * 10))
Console.WriteLine(string.Join(", ", window));
// => 10, 20, 30
// => 40, 50, 60
// => 70, 80, 90
// Compute count and sum in a single pass.
var (count, sum) = source.Aggregate(
seed1: 0,
seed2: 0L,
func1: (c, _) => c + 1,
func2: (s, x) => s + x); // => count == 9, sum == 45
// Predicate-style set check using a custom comparer.
bool anyMatch = new[] { "FOO", "bar" }
.ContainsAny(new[] { "foo", "baz" }, StringComparer.OrdinalIgnoreCase); // => true
Methods
Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, int, TAccumulate>)
Applies an accumulator function over a sequence using the specified seed as the initial accumulator value, incorporating the element's index.
public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, int, TAccumulate> func)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seedTAccumulateThe initial accumulator value.
funcFunc<TAccumulate, TSource, int, TAccumulate>An accumulator function invoked on each element. The first argument is the running aggregate, the second is the current element, and the third is the zero-based index of the current element.
Returns
- TAccumulate
The final accumulator value.
Type Parameters
TSourceThe type of the elements contained in the sequence.
TAccumulateThe type of the accumulator value.
Remarks
If source is empty, seed is returned unchanged and
func is not invoked.
The index starts at zero and increments by one for each element visited. The counter is incremented using a checked operation so overflow throws rather than wraps.
Exceptions
- ArgumentNullException
Thrown when
sourceorfuncis null.
Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, int, TAccumulate>, Func<TAccumulate, TResult>)
Applies an accumulator function over a sequence using the specified seed as the initial accumulator value, incorporating the element's index, and projects the final accumulator value through the supplied result selector.
public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, int, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seedTAccumulateThe initial accumulator value.
funcFunc<TAccumulate, TSource, int, TAccumulate>An accumulator function invoked on each element. The first argument is the running aggregate, the second is the current element, and the third is the zero-based index of the current element.
resultSelectorFunc<TAccumulate, TResult>A function that transforms the final accumulator value into the returned result.
Returns
- TResult
The value produced by applying
resultSelectorto the final accumulator value.
Type Parameters
TSourceThe type of the elements contained in the sequence.
TAccumulateThe type of the accumulator value.
TResultThe type of the resulting value.
Remarks
If source is empty, resultSelector is applied to
seed.
Exceptions
- ArgumentNullException
Thrown when
source,func, orresultSelectoris null.
Aggregate<TSource, T1, T2>(IEnumerable<TSource>, T1, T2, Func<T1, TSource, int, T1>, Func<T2, TSource, int, T2>)
Applies two accumulator functions over a sequence in a single pass, incorporating the element's index, and returns the final accumulator values as a tuple.
public static (T1, T2) Aggregate<TSource, T1, T2>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, Func<T1, TSource, int, T1> func1, Func<T2, TSource, int, T2> func2)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
func1Func<T1, TSource, int, T1>An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.
func2Func<T2, TSource, int, T2>An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.
Returns
- (T1, T2)
A tuple containing the final values of both accumulators.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
Remarks
The sequence is enumerated exactly once. Both functions receive the same zero-based index for a given element
and func1 is invoked before func2. The counter is incremented using a
checked operation so overflow throws rather than wraps.
Exceptions
- ArgumentNullException
Thrown when
source,func1, orfunc2is null.
Aggregate<TSource, T1, T2>(IEnumerable<TSource>, T1, T2, Func<T1, TSource, T1>, Func<T2, TSource, T2>)
Applies two accumulator functions over a sequence in a single pass and returns the final accumulator values as a tuple.
public static (T1, T2) Aggregate<TSource, T1, T2>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, Func<T1, TSource, T1> func1, Func<T2, TSource, T2> func2)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
func1Func<T1, TSource, T1>An accumulator function invoked on each element for the first accumulator.
func2Func<T2, TSource, T2>An accumulator function invoked on each element for the second accumulator.
Returns
- (T1, T2)
A tuple containing the final values of both accumulators.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
Examples
var (min, max) = new[] { 3, 1, 4, 1, 5, 9, 2, 6 }.Aggregate(
seed1: int.MaxValue,
seed2: int.MinValue,
func1: (acc, x) => Math.Min(acc, x),
func2: (acc, x) => Math.Max(acc, x)); // min == 1, max == 9
Remarks
The sequence is enumerated exactly once. For each element, func1 is invoked before
func2. If source is empty, the seeds are returned unchanged.
Exceptions
- ArgumentNullException
Thrown when
source,func1, orfunc2is null.
Aggregate<TSource, T1, T2, TResult>(IEnumerable<TSource>, T1, T2, Func<T1, TSource, int, T1>, Func<T2, TSource, int, T2>, Func<T1, T2, TResult>)
Applies two accumulator functions over a sequence in a single pass, incorporating the element's index, and projects the final accumulator values through the supplied result selector.
public static TResult Aggregate<TSource, T1, T2, TResult>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, Func<T1, TSource, int, T1> func1, Func<T2, TSource, int, T2> func2, Func<T1, T2, TResult> resultSelector)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
func1Func<T1, TSource, int, T1>An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.
func2Func<T2, TSource, int, T2>An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.
resultSelectorFunc<T1, T2, TResult>A function that transforms the final accumulator values into the returned result.
Returns
- TResult
The value produced by applying
resultSelectorto the final accumulator values.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
TResultThe type of the resulting value.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2, orresultSelectoris null.
Aggregate<TSource, T1, T2, TResult>(IEnumerable<TSource>, T1, T2, Func<T1, TSource, T1>, Func<T2, TSource, T2>, Func<T1, T2, TResult>)
Applies two accumulator functions over a sequence in a single pass and projects the final accumulator values through the supplied result selector.
public static TResult Aggregate<TSource, T1, T2, TResult>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, Func<T1, TSource, T1> func1, Func<T2, TSource, T2> func2, Func<T1, T2, TResult> resultSelector)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
func1Func<T1, TSource, T1>An accumulator function invoked on each element for the first accumulator.
func2Func<T2, TSource, T2>An accumulator function invoked on each element for the second accumulator.
resultSelectorFunc<T1, T2, TResult>A function that transforms the final accumulator values into the returned result.
Returns
- TResult
The value produced by applying
resultSelectorto the final accumulator values.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
TResultThe type of the resulting value.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2, orresultSelectoris null.
Aggregate<TSource, T1, T2, T3>(IEnumerable<TSource>, T1, T2, T3, Func<T1, TSource, int, T1>, Func<T2, TSource, int, T2>, Func<T3, TSource, int, T3>)
Applies three accumulator functions over a sequence in a single pass, incorporating the element's index, and returns the final accumulator values as a tuple.
public static (T1, T2, T3) Aggregate<TSource, T1, T2, T3>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, T3 seed3, Func<T1, TSource, int, T1> func1, Func<T2, TSource, int, T2> func2, Func<T3, TSource, int, T3> func3)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
seed3T3The initial value of the third accumulator.
func1Func<T1, TSource, int, T1>An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.
func2Func<T2, TSource, int, T2>An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.
func3Func<T3, TSource, int, T3>An accumulator function invoked on each element for the third accumulator; receives the element's index as its third argument.
Returns
- (T1, T2, T3)
A tuple containing the final values of the three accumulators.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
T3The type of the third accumulator value.
Remarks
The sequence is enumerated exactly once. All three functions receive the same zero-based index for a given element and are invoked in declaration order. The counter is incremented using a checked operation so overflow throws rather than wraps.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2, orfunc3is null.
Aggregate<TSource, T1, T2, T3>(IEnumerable<TSource>, T1, T2, T3, Func<T1, TSource, T1>, Func<T2, TSource, T2>, Func<T3, TSource, T3>)
Applies three accumulator functions over a sequence in a single pass and returns the final accumulator values as a tuple.
public static (T1, T2, T3) Aggregate<TSource, T1, T2, T3>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, T3 seed3, Func<T1, TSource, T1> func1, Func<T2, TSource, T2> func2, Func<T3, TSource, T3> func3)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
seed3T3The initial value of the third accumulator.
func1Func<T1, TSource, T1>An accumulator function invoked on each element for the first accumulator.
func2Func<T2, TSource, T2>An accumulator function invoked on each element for the second accumulator.
func3Func<T3, TSource, T3>An accumulator function invoked on each element for the third accumulator.
Returns
- (T1, T2, T3)
A tuple containing the final values of the three accumulators.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
T3The type of the third accumulator value.
Examples
var (sum, count, max) = new[] { 3, 1, 4, 1, 5, 9, 2, 6 }.Aggregate(
seed1: 0,
seed2: 0,
seed3: int.MinValue,
func1: (acc, x) => acc + x,
func2: (acc, _) => acc + 1,
func3: (acc, x) => Math.Max(acc, x)); // sum == 31, count == 8, max == 9
Remarks
The sequence is enumerated exactly once. For each element, func1, func2,
and func3 are invoked in declaration order. If source is empty, the
seeds are returned unchanged.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2, orfunc3is null.
Aggregate<TSource, T1, T2, T3, TResult>(IEnumerable<TSource>, T1, T2, T3, Func<T1, TSource, int, T1>, Func<T2, TSource, int, T2>, Func<T3, TSource, int, T3>, Func<T1, T2, T3, TResult>)
Applies three accumulator functions over a sequence in a single pass, incorporating the element's index, and projects the final accumulator values through the supplied result selector.
public static TResult Aggregate<TSource, T1, T2, T3, TResult>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, T3 seed3, Func<T1, TSource, int, T1> func1, Func<T2, TSource, int, T2> func2, Func<T3, TSource, int, T3> func3, Func<T1, T2, T3, TResult> resultSelector)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
seed3T3The initial value of the third accumulator.
func1Func<T1, TSource, int, T1>An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.
func2Func<T2, TSource, int, T2>An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.
func3Func<T3, TSource, int, T3>An accumulator function invoked on each element for the third accumulator; receives the element's index as its third argument.
resultSelectorFunc<T1, T2, T3, TResult>A function that transforms the final accumulator values into the returned result.
Returns
- TResult
The value produced by applying
resultSelectorto the final accumulator values.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
T3The type of the third accumulator value.
TResultThe type of the resulting value.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2,func3, orresultSelectoris null.
Aggregate<TSource, T1, T2, T3, TResult>(IEnumerable<TSource>, T1, T2, T3, Func<T1, TSource, T1>, Func<T2, TSource, T2>, Func<T3, TSource, T3>, Func<T1, T2, T3, TResult>)
Applies three accumulator functions over a sequence in a single pass and projects the final accumulator values through the supplied result selector.
public static TResult Aggregate<TSource, T1, T2, T3, TResult>(this IEnumerable<TSource> source, T1 seed1, T2 seed2, T3 seed3, Func<T1, TSource, T1> func1, Func<T2, TSource, T2> func2, Func<T3, TSource, T3> func3, Func<T1, T2, T3, TResult> resultSelector)
Parameters
sourceIEnumerable<TSource>An IEnumerable<T> to aggregate over.
seed1T1The initial value of the first accumulator.
seed2T2The initial value of the second accumulator.
seed3T3The initial value of the third accumulator.
func1Func<T1, TSource, T1>An accumulator function invoked on each element for the first accumulator.
func2Func<T2, TSource, T2>An accumulator function invoked on each element for the second accumulator.
func3Func<T3, TSource, T3>An accumulator function invoked on each element for the third accumulator.
resultSelectorFunc<T1, T2, T3, TResult>A function that transforms the final accumulator values into the returned result.
Returns
- TResult
The value produced by applying
resultSelectorto the final accumulator values.
Type Parameters
TSourceThe type of the elements contained in the sequence.
T1The type of the first accumulator value.
T2The type of the second accumulator value.
T3The type of the third accumulator value.
TResultThe type of the resulting value.
Exceptions
- ArgumentNullException
Thrown when
source,func1,func2,func3, orresultSelectoris null.
BatchPooled<TSource>(IEnumerable<TSource>, int)
Batches a sequence using a pooled array to reduce allocations.
public static IEnumerable<ReadOnlyMemory<TSource>> BatchPooled<TSource>(this IEnumerable<TSource> source, int size)
Parameters
sourceIEnumerable<TSource>The source sequence to batch.
sizeintThe maximum number of items per batch.
Returns
- IEnumerable<ReadOnlyMemory<TSource>>
An IEnumerable<T> of ReadOnlyMemory<T> batches that alias a single pooled buffer, so a full enumeration allocates nothing per batch.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Input: Enumerable.Range(1, 9)
// Batch size: 3
// Expected output:
// Batch 1: 1, 2, 3
// Batch 2: 4, 5, 6
// Batch 3: 7, 8, 9
var source = Enumerable.Range(1, 9);
foreach (var batch in source.BatchPooled(3))
{
Console.WriteLine(string.Join(", ", batch.ToArray()));
}
Remarks
This overload returns untransformed batches of the original element type. Each batch is valid only until the enumerator advances - see BatchPooled<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, int, TResult>) for the full lifetime contract and for a variant that applies a projection.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.- ArgumentOutOfRangeException
Thrown when
sizeis less than or equal to 0.
BatchPooled<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, int, TResult>)
Batches and transforms a sequence using a pooled array to reduce allocations.
public static IEnumerable<ReadOnlyMemory<TResult>> BatchPooled<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<TSource, int, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to batch.
sizeintThe maximum number of items per batch.
selectorFunc<TSource, int, TResult>A projection function that receives the source item and its index.
Returns
- IEnumerable<ReadOnlyMemory<TResult>>
An IEnumerable<T> of ReadOnlyMemory<T> batches that alias a single pooled buffer, so a full enumeration allocates nothing per batch.
Type Parameters
TSourceThe type of elements in the source sequence.
TResultThe type of transformed result.
Examples
// Input: Enumerable.Range(1, 10)
// Batch size: 4
// Selector: (x, i) => $"Item {i}: {x}"
// Expected output:
// Batch 1: "Item 0: 1", "Item 1: 2", "Item 2: 3", "Item 3: 4"
// Batch 2: "Item 4: 5", "Item 5: 6", "Item 6: 7", "Item 7: 8"
// Batch 3: "Item 8: 9", "Item 9: 10"
var source = Enumerable.Range(1, 10);
foreach (var batch in source.BatchPooled(4, (x, i) => $"Item {i}: {x}"))
{
Console.WriteLine($"[{string.Join(", ", batch.ToArray())}]");
}
Remarks
Every yielded batch is a window over the same pooled buffer, which is overwritten by the next iteration
step and returned to the pool when enumeration ends. A batch is therefore valid only until the enumerator
advances (or is disposed): to retain one, copy it with .ToArray() before advancing. Retaining the
ReadOnlyMemory<T> values themselves - for example via ToList() on the returned sequence -
observes overwritten or recycled data. For independently owned batches, use
Chunk<TSource>(IEnumerable<TSource>, int) or the projecting
Batch<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, TResult>) overload instead.
This method should be consumed via foreach. Each enumeration rents one buffer of size
elements for its duration.
Exceptions
- ArgumentNullException
Thrown when
sourceorselectoris null.- ArgumentOutOfRangeException
Thrown when
sizeis less than or equal to 0.
Batch<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, int, TResult>)
Projects each element of a sequence into a new form using its index, and batches the transformed elements into subsequences of the specified size.
public static IEnumerable<IEnumerable<TResult>> Batch<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<TSource, int, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to batch.
sizeintThe size of each batch. Must be greater than 0.
selectorFunc<TSource, int, TResult>A projection function that receives the item and its index.
Returns
- IEnumerable<IEnumerable<TResult>>
An IEnumerable<T> where each inner IEnumerable<T> contains up to
sizetransformed elements.
Type Parameters
TSourceThe type of elements in the source sequence.
TResultThe type of result elements.
Remarks
This method uses deferred execution. The projection and batching occur only during enumeration.
Exceptions
- ArgumentNullException
Thrown when
sourceorselectoris null.- ArgumentOutOfRangeException
Thrown when
sizeis less than or equal to 0.
Batch<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, TResult>)
Projects each element of a sequence and batches the transformed elements into subsequences of the specified size.
public static IEnumerable<IEnumerable<TResult>> Batch<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<TSource, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to batch.
sizeintThe size of each batch. Must be greater than 0.
selectorFunc<TSource, TResult>A projection function to apply to each element.
Returns
- IEnumerable<IEnumerable<TResult>>
An IEnumerable<T> where each inner IEnumerable<T> contains up to
sizetransformed elements.
Type Parameters
TSourceThe type of elements in the source sequence.
TResultThe type of result elements.
Remarks
This method uses deferred execution. The transformation and batching occur only during enumeration. For plain, unprojected batching, use Chunk<TSource>(IEnumerable<TSource>, int).
Exceptions
- ArgumentNullException
Thrown when
sourceorselectoris null.- ArgumentOutOfRangeException
Thrown when
sizeis less than or equal to 0.
Cache<T>(IEnumerable<T>)
Produces a sequence that lazily caches the elements of the source as it is iterated for the first time. Subsequent iteration requests return the cached elements.
public static IEnumerable<T> Cache<T>(this IEnumerable<T> source)
Parameters
sourceIEnumerable<T>The sequence whose elements should be cached.
Returns
- IEnumerable<T>
An IEnumerable<T> that caches the source's elements on first enumeration and returns cached results on all subsequent enumerations.
Type Parameters
TThe type of the elements in the source sequence.
Remarks
This method uses deferred execution. The caching begins only when the resulting sequence is enumerated. If the source is already a collection or an existing cached sequence, no additional wrapping is performed.
Source-enumerator lifetime. The wrapper holds the source's enumerator open from the first enumeration until the source is fully consumed. Although the wrapper implements IDisposable, that surface is not reachable through the returned IEnumerable<T> - disposing an individual enumerator does not release the source. A partially consumed cache that is then abandoned therefore pins the source enumerator (and whatever it holds) until the wrapper is garbage collected, unless the caller casts the returned sequence to IDisposable and disposes it explicitly.
Initialization faults. If the source's GetEnumerator() throws, the captured exception poisons the cache: it is rethrown for every later enumeration attempt rather than retrying the source. Disposing the wrapper (via the IDisposable cast) clears the poisoned state.
Disposal re-arms. Disposing the wrapper releases the source enumerator and cached elements and resets the wrapper to its uninitialized state: live enumerators observe ObjectDisposedException, and a subsequent enumeration re-enumerates the source from scratch rather than failing.
Exceptions
- ArgumentNullException
sourceis null.
CartesianProduct<TFirst, TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>)
Emits the Cartesian product of two sequences as (First, Second) tuples, pairing every element of the
first sequence with every element of the second.
public static IEnumerable<(TFirst First, TSecond Second)> CartesianProduct<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second)
Parameters
firstIEnumerable<TFirst>The first sequence, whose elements drive the outer loop of the product.
secondIEnumerable<TSecond>The second sequence, whose elements drive the inner loop of the product.
Returns
- IEnumerable<(TFirst First, TSecond Second)>
A sequence of
(First, Second)tuples containing every pairing, ordered by the position of the first element and then by the position of the second. The result is empty when either input is empty.
Type Parameters
TFirstThe type of elements in the first sequence.
TSecondThe type of elements in the second sequence.
Examples
// Pair every number with every letter.
foreach (var (number, letter) in new[] { 1, 2 }.CartesianProduct(new[] { "a", "b" }))
Console.WriteLine($"{number}{letter}");
// => 1a
// => 1b
// => 2a
// => 2b
Remarks
This method uses deferred execution. first is streamed and enumerated exactly once;
second is materialized into a buffer the first time a product row is needed and every
subsequent pass replays that buffer, so second is also enumerated exactly once. When
first is empty, second is never enumerated.
Because second is buffered in full, it must be finite; first may be
infinite and bounded downstream with
Take<TSource>(IEnumerable<TSource>, int).
Exceptions
- ArgumentNullException
Thrown when
firstorsecondis null.
CartesianProduct<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst, TSecond, TResult>)
Applies a projection to every pairing in the Cartesian product of two sequences.
public static IEnumerable<TResult> CartesianProduct<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
Parameters
firstIEnumerable<TFirst>The first sequence, whose elements drive the outer loop of the product.
secondIEnumerable<TSecond>The second sequence, whose elements drive the inner loop of the product.
resultSelectorFunc<TFirst, TSecond, TResult>A projection applied to each pairing, receiving the first-sequence element and the second-sequence element.
Returns
- IEnumerable<TResult>
A sequence containing the result of
resultSelectorapplied to every pairing, ordered by the position of the first element and then by the position of the second. The result is empty when either input is empty.
Type Parameters
TFirstThe type of elements in the first sequence.
TSecondThe type of elements in the second sequence.
TResultThe type of the projected result.
Examples
// Project each pairing into a formatted coordinate.
string[] cells = new[] { 'A', 'B' }.CartesianProduct(new[] { 1, 2 }, (column, row) => $"{column}{row}").ToArray();
// => cells == [ "A1", "A2", "B1", "B2" ]
Remarks
This method uses deferred execution. first is streamed and enumerated exactly once;
second is materialized into a buffer the first time a product row is needed and every
subsequent pass replays that buffer, so second is also enumerated exactly once. When
first is empty, second is never enumerated.
resultSelector is invoked exactly once per emitted pairing and is never invoked when either
input is empty.
Exceptions
- ArgumentNullException
Thrown when
first,second, orresultSelectoris null.
ChunkBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>)
Groups adjacent elements of the source sequence that share the same key, starting a new group whenever the key changes, using the default equality comparer.
public static IEnumerable<(TKey Key, IReadOnlyList<TSource> Items)> ChunkBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
Parameters
sourceIEnumerable<TSource>The source sequence to group.
keySelectorFunc<TSource, TKey>A function that produces the grouping key for each element.
Returns
- IEnumerable<(TKey Key, IReadOnlyList<TSource> Items)>
A sequence of
(Key, Items)tuples whereItemsis a stable snapshot of a maximal run of adjacent elements sharingKey. The result is empty whensourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
TKeyThe type of the key produced for each element.
Examples
// Group adjacent runs by key; a repeated key separated by another key starts a new group.
foreach (var (key, items) in new[] { 1, 1, 2, 1 }.ChunkBy(x => x))
Console.WriteLine($"{key}: [{string.Join(", ", items)}]");
// => 1: [1, 1]
// => 2: [2]
// => 1: [1]
Remarks
This method uses deferred execution and enumerates the source exactly once. Keys are compared with Default.
Exceptions
- ArgumentNullException
Thrown when
sourceorkeySelectoris null.
ChunkBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>?)
Groups adjacent elements of the source sequence that share the same key, starting a new group whenever the key changes, using the specified equality comparer.
public static IEnumerable<(TKey Key, IReadOnlyList<TSource> Items)> ChunkBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey>? comparer)
Parameters
sourceIEnumerable<TSource>The source sequence to group.
keySelectorFunc<TSource, TKey>A function that produces the grouping key for each element.
comparerIEqualityComparer<TKey>The comparer used to decide whether adjacent keys are equal, or null to use Default.
Returns
- IEnumerable<(TKey Key, IReadOnlyList<TSource> Items)>
A sequence of
(Key, Items)tuples whereItemsis a stable snapshot of a maximal run of adjacent elements sharingKey. The result is empty whensourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
TKeyThe type of the key produced for each element.
Remarks
This method uses deferred execution and enumerates the source exactly once in a single forward pass, buffering
only the current group. keySelector is invoked exactly once per source element, and each
yielded group is a stable snapshot that is not modified when the enumerator advances.
This method differs from
GroupBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>):
GroupBy gathers all elements sharing a key across the whole sequence, whereas this method uses adjacent
equality only, so the same key value separated by a different key produces separate groups.
When bounded over an infinite source, a group whose key never changes never yields; combine with Take<TSource>(IEnumerable<TSource>, int) only when keys are known to change.
Exceptions
- ArgumentNullException
Thrown when
sourceorkeySelectoris null.
Combinations<TSource>(IEnumerable<TSource>, int)
Emits every combination of the specified size drawn from the source sequence (the k-subsets), each preserving source order within the row.
public static IEnumerable<IReadOnlyList<TSource>> Combinations<TSource>(this IEnumerable<TSource> source, int size)
Parameters
sourceIEnumerable<TSource>The source sequence to draw combinations from.
sizeintThe number of elements in each combination row. Must not be negative.
Returns
- IEnumerable<IReadOnlyList<TSource>>
A sequence of C(n, k) rows for a source of n elements, each row a fresh IReadOnlyList<T> snapshot of exactly
sizeelements in source order. Whensizeis 0 the result contains a single empty row; whensizeexceeds the source count the result is empty.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Emit all C(4, 2) = 6 subsets of two elements.
foreach (var row in new[] { 1, 2, 3, 4 }.Combinations(2))
Console.WriteLine(string.Join(", ", row));
// => 1, 2
// => 1, 3
// => 1, 4
// => 2, 3
// => 2, 4
// => 3, 4
Remarks
This method uses deferred execution. Negative size values are rejected eagerly at the call
site, but the source count is only known once enumeration begins, so the size > count contract -
producing an empty sequence rather than throwing - is observed on iteration. The source is materialized into a
buffer when enumeration begins and is enumerated exactly once.
Rows are ordered lexicographically by the source positions they select: the first row is the first
size elements, and the last row is the final size elements. Elements are
treated positionally, so duplicate values produce duplicate rows. Each row is an independent snapshot -
retaining or mutating one row never affects another. A size of 0 yields exactly one empty
row, matching the mathematical convention that C(n, 0) = 1.
Unlike Permutations<TSource>(IEnumerable<TSource>, int), element order within a row is not significant: each subset appears exactly once, with its elements in source order.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.- ArgumentOutOfRangeException
Thrown when
sizeis negative.
ContainsAll<T>(IEnumerable<T>, IEnumerable<T>, IEqualityComparer<T>?)
Determines whether the source sequence contains all of the specified items.
public static bool ContainsAll<T>(this IEnumerable<T> source, IEnumerable<T> items, IEqualityComparer<T>? comparer = null)
Parameters
sourceIEnumerable<T>The source sequence to search.
itemsIEnumerable<T>The items to verify against the source sequence.
comparerIEqualityComparer<T>An optional equality comparer to use; if null, the default comparer is used.
Returns
Type Parameters
TThe type of elements in the sequences.
Remarks
Memory use scales with the number of items, not the size of source: the
items are collected into a pending set and source is streamed with a single enumeration,
stopping as soon as every item has been seen.
Exceptions
- ArgumentNullException
Thrown if either
sourceoritemsis null.
ContainsAny<T>(IEnumerable<T>, IEnumerable<T>, IEqualityComparer<T>?)
Determines whether the source sequence contains any of the specified items.
public static bool ContainsAny<T>(this IEnumerable<T> source, IEnumerable<T> items, IEqualityComparer<T>? comparer = null)
Parameters
sourceIEnumerable<T>The source sequence to search.
itemsIEnumerable<T>The items to locate within the source sequence.
comparerIEqualityComparer<T>An optional equality comparer to use for element comparisons; if null, the default comparer is used.
Returns
Type Parameters
TThe type of elements in the sequences.
Remarks
This method avoids repeated enumeration of either sequence by building a HashSet<T> for O(1) membership lookups.
The set is built from whichever collection has fewer elements, when both sizes are known, to minimize allocation
and fill cost. When sizes are unknown or equal, the set is built from items, which is always
materialized and is typically the smaller "needle" set in common usage.
Exceptions
- ArgumentNullException
Thrown if either
sourceoritemsis null.
ForEach<TSource>(IEnumerable<TSource>, Action<TSource>)
Invokes action once for each element of source, in sequence order.
public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
Parameters
sourceIEnumerable<TSource>The sequence whose elements are passed to
action.actionAction<TSource>The delegate invoked for each element.
Type Parameters
TSourceThe type of the elements of
source.
Remarks
Execution is eager: source is enumerated to completion before the method returns, and is
enumerated exactly once.
Exceptions
- ArgumentNullException
Thrown when
sourceoractionis null.
Index<TSource>(IEnumerable<TSource>)
.NET 8 only
Pairs each element of source with its zero-based position in the sequence.
public static IEnumerable<(int Index, TSource Item)> Index<TSource>(this IEnumerable<TSource> source)
Parameters
sourceIEnumerable<TSource>The sequence to pair with positional indexes.
Returns
- IEnumerable<(int Index, TSource Item)>
A sequence of tuples, each holding the zero-based index and the element at that position, in order.
Type Parameters
TSourceThe type of the elements of
source.
Remarks
Execution is deferred: source is not enumerated until the returned sequence is iterated,
while the null argument check runs eagerly.
This helper is compiled only for targets earlier than .NET 9, where the runtime introduces an equivalent
Enumerable.Index method on the standard LINQ surface.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
Interleave<TSource>(IEnumerable<TSource>, params IEnumerable<TSource>[])
Interleaves the source sequence with one or more additional sequences, taking one element from each sequence in turn and skipping sequences as they are exhausted.
public static IEnumerable<TSource> Interleave<TSource>(this IEnumerable<TSource> first, params IEnumerable<TSource>[] others)
Parameters
firstIEnumerable<TSource>The first sequence, which contributes the first element of each round.
othersIEnumerable<TSource>[]The additional sequences to interleave after
first. Must not contain null elements.
Returns
- IEnumerable<TSource>
A sequence containing every element of every input, ordered in rounds: each round takes one element from each not-yet-exhausted input, starting with
firstand continuing throughothersin order. The result length is the sum of the input lengths.
Type Parameters
TSourceThe type of elements in the sequences.
Examples
// Rounds continue with the surviving inputs once shorter ones are exhausted.
int[] result = new[] { 1, 2, 3 }.Interleave(new[] { 10, 20 }, new[] { 100 }).ToArray();
// => result == [ 1, 10, 100, 2, 20, 3 ]
Remarks
This method uses deferred execution for the elements, but validates its arguments eagerly: a
null entry in others throws at the call site, not during iteration. Each
input is enumerated exactly once and its enumerator is disposed, including when the result is abandoned early.
Inputs of unequal length do not truncate the result and do not throw: once an input is exhausted it is skipped
and the remaining inputs continue round-robin until all are exhausted. This is the round-robin scheduling
shape - fair rotation over the surviving inputs - so no separate RoundRobin operator is provided.
Exceptions
- ArgumentNullException
Thrown when
firstorothersis null.- ArgumentException
Thrown when
otherscontains a null element.
IsNullOrEmpty<TSource>(IEnumerable<TSource>?)
Determines whether source is null or contains no elements.
public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource>? source)
Parameters
sourceIEnumerable<TSource>The sequence to test. May be null.
Returns
Type Parameters
TSourceThe type of the elements of
source.
Remarks
When source implements ICollection<T> or
IReadOnlyCollection<T> the element count is read directly; otherwise the sequence is probed for a
single element. A non-counted sequence is advanced by at most one step and is never fully enumerated.
Pairwise<TSource>(IEnumerable<TSource>)
Emits each adjacent pair of elements from the source sequence as a (Previous, Current) tuple.
public static IEnumerable<(TSource Previous, TSource Current)> Pairwise<TSource>(this IEnumerable<TSource> source)
Parameters
sourceIEnumerable<TSource>The source sequence to pair.
Returns
- IEnumerable<(TSource Previous, TSource Current)>
A sequence of
(Previous, Current)tuples, one for every adjacent pair of elements insource. The result is empty whensourcecontains fewer than two elements.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Emit each adjacent (previous, current) pair.
foreach (var (previous, current) in new[] { 10, 13, 9 }.Pairwise())
Console.WriteLine($"{previous} -> {current}");
// => 10 -> 13
// => 13 -> 9
Remarks
This method uses deferred execution. The source sequence is not enumerated until the returned sequence is enumerated, and it is enumerated exactly once in a single forward pass using only O(1) working memory.
This is the primitive for neighbour comparison - monotonic checks, gap detection, deltas, and change detection. Because only the previous element is retained, the operator can be bounded over an infinite source with Take<TSource>(IEnumerable<TSource>, int).
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
Pairwise<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TSource, TResult>)
Applies a projection to each adjacent pair of elements from the source sequence.
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to pair.
selectorFunc<TSource, TSource, TResult>A projection applied to each adjacent pair, receiving the previous and current elements.
Returns
- IEnumerable<TResult>
A sequence containing the result of
selectorapplied to every adjacent pair of elements insource. The result is empty whensourcecontains fewer than two elements.
Type Parameters
TSourceThe type of elements in the source sequence.
TResultThe type of the projected result.
Examples
// Project each adjacent pair into the delta between the two values.
int[] deltas = new[] { 10, 13, 9 }.Pairwise((previous, current) => current - previous).ToArray();
// => deltas == [ 3, -4 ]
Remarks
This method uses deferred execution. The source sequence is not enumerated until the returned sequence is enumerated, and it is enumerated exactly once in a single forward pass using only O(1) working memory.
selector is invoked exactly once per emitted pair and is never invoked for an empty or
single-element source.
Exceptions
- ArgumentNullException
Thrown when
sourceorselectoris null.
Permutations<TSource>(IEnumerable<TSource>)
Emits every full permutation of the source sequence, one row per distinct ordering of all elements.
public static IEnumerable<IReadOnlyList<TSource>> Permutations<TSource>(this IEnumerable<TSource> source)
Parameters
sourceIEnumerable<TSource>The source sequence to permute.
Returns
- IEnumerable<IReadOnlyList<TSource>>
A sequence of n! rows for a source of n elements, each row a fresh IReadOnlyList<T> snapshot containing all elements in one ordering. An empty source yields a single empty row (the empty permutation).
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Emit all 3! orderings of the source.
foreach (var row in new[] { 1, 2, 3 }.Permutations())
Console.WriteLine(string.Join(", ", row));
// => 1, 2, 3
// => 1, 3, 2
// => 2, 1, 3
// => 2, 3, 1
// => 3, 1, 2
// => 3, 2, 1
Remarks
This method uses deferred execution. The source is materialized into a buffer when enumeration of the result begins and is enumerated exactly once; rows are then generated on demand without precomputing the full set.
Rows are ordered lexicographically by the source positions they select: the first row preserves source order, and each subsequent row is the next arrangement in position order. Elements are treated positionally, so duplicate values produce duplicate rows. Each row is an independent snapshot - retaining or mutating one row never affects another.
The row count grows factorially with the source length; bound the result with Take<TSource>(IEnumerable<TSource>, int) when the source may be large.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
Permutations<TSource>(IEnumerable<TSource>, int)
Emits every permutation of the specified size drawn from the source sequence (the k-permutations).
public static IEnumerable<IReadOnlyList<TSource>> Permutations<TSource>(this IEnumerable<TSource> source, int size)
Parameters
sourceIEnumerable<TSource>The source sequence to permute.
sizeintThe number of elements in each permutation row. Must not be negative.
Returns
- IEnumerable<IReadOnlyList<TSource>>
A sequence of P(n, k) rows for a source of n elements, each row a fresh IReadOnlyList<T> snapshot of exactly
sizeelements. Whensizeis 0 the result contains a single empty row; whensizeexceeds the source count the result is empty.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Emit all P(3, 2) = 6 ordered selections of two elements.
foreach (var row in new[] { 1, 2, 3 }.Permutations(2))
Console.WriteLine(string.Join(", ", row));
// => 1, 2
// => 1, 3
// => 2, 1
// => 2, 3
// => 3, 1
// => 3, 2
Remarks
This method uses deferred execution. Negative size values are rejected eagerly at the call
site, but the source count is only known once enumeration begins, so the size > count contract -
producing an empty sequence rather than throwing - is observed on iteration. The source is materialized into a
buffer when enumeration begins and is enumerated exactly once.
Rows are ordered lexicographically by the source positions they select. Elements are treated positionally, so
duplicate values produce duplicate rows. Each row is an independent snapshot - retaining or mutating one row
never affects another. A size of 0 yields exactly one empty row, matching the mathematical
convention that P(n, 0) = 1.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.- ArgumentOutOfRangeException
Thrown when
sizeis negative.
Randomize<T>(IEnumerable<T>, RandomizationMode, IRandomGenerator, int?)
Randomizes the source sequence using a specified strategy and random number generator.
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source, RandomizationMode mode, IRandomGenerator rng, int? count = null)
Parameters
sourceIEnumerable<T>The sequence to randomize.
modeRandomizationModeThe randomization strategy to apply.
rngIRandomGeneratorThe random number generator to use.
countint?The number of items to return; returns all items when null.
Returns
- IEnumerable<T>
A randomized sequence of
T.
Type Parameters
TThe element type.
Remarks
Execution is deferred until the returned sequence is enumerated for every mode. Null checks for
source and rng, validation that count is not
negative, and the mode-dependent requirement for a non-null
count are performed eagerly; validation that count does not exceed the
number of available elements is performed during enumeration.
Under StreamWindowed, a non-null count
limits the randomized stream to that many elements; if the source is exhausted first,
ArgumentOutOfRangeException is thrown during enumeration, consistent with the other modes.
To shuffle a fully materialized collection in place - the buffer-everything strategy - use the BCL
Shuffle<T>(Span<T>) (or Random.Shared.Shuffle) instead; every
RandomizationMode here bounds memory use below the full source length.
Exceptions
- ArgumentNullException
Thrown if
sourceorrngis null.- ArgumentOutOfRangeException
Thrown if
countis negative, exceeds the number of available elements, or ifmodeis not a defined RandomizationMode value.- ArgumentException
Thrown if
countis null andmoderequires a count (i.e. ReservoirSample or LazyShuffle).
RecursiveSelect<TSource>(IEnumerable<TSource>, Func<TSource, IEnumerable<TSource>>)
Recursively flattens a hierarchical sequence using the provided child selector.
public static IEnumerable<TSource> RecursiveSelect<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector)
Parameters
sourceIEnumerable<TSource>The root sequence to begin recursion from.
childSelectorFunc<TSource, IEnumerable<TSource>>A function that returns child elements for a given element.
Returns
- IEnumerable<TSource>
A flattened sequence of all elements including their children.
Type Parameters
TSourceThe type of the elements in the sequence.
Examples
var allNodes = rootNodes.RecursiveSelect(node => node.Children);
Exceptions
- ArgumentNullException
Thrown if
sourceorchildSelectoris null.
RecursiveSelect<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TSource>>, Func<TSource, int, int, TResult>)
Recursively flattens and transforms a hierarchical sequence using child selector and a selector that receives index and depth.
public static IEnumerable<TResult> RecursiveSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, Func<TSource, int, int, TResult> selector)
Parameters
sourceIEnumerable<TSource>The root sequence to begin recursion from.
childSelectorFunc<TSource, IEnumerable<TSource>>A function that returns child elements for a given element.
selectorFunc<TSource, int, int, TResult>A transform applied to each element, receiving index and depth.
Returns
- IEnumerable<TResult>
A flattened and projected sequence from all elements including children.
Type Parameters
TSourceThe type of the source elements.
TResultThe type of the result elements.
Examples
var formatted = rootNodes.RecursiveSelect(
node => node.Children,
(node, index, depth) => new { node.Name, index, depth });
Exceptions
- ArgumentNullException
Thrown if
source,childSelector, orselectoris null.
RecursiveSelect<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TSource>>, Func<TSource, int, int, TResult>, Func<TSource, RecursiveSelectControl>)
Recursively flattens and transforms a hierarchical sequence with depth/index tracking and a delegate that returns a RecursiveSelectControl value to control yielding, recursion, and termination at each node.
public static IEnumerable<TResult> RecursiveSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, Func<TSource, int, int, TResult> selector, Func<TSource, RecursiveSelectControl> recursionControl)
Parameters
sourceIEnumerable<TSource>The root sequence to begin recursion from.
childSelectorFunc<TSource, IEnumerable<TSource>>A function that returns child elements for a given element.
selectorFunc<TSource, int, int, TResult>A transform function applied to each element with index and depth.
recursionControlFunc<TSource, RecursiveSelectControl>A delegate that returns a RecursiveSelectControl value for each element, indicating whether to yield it, recurse into its children, stop processing sibling elements at the current level, or terminate traversal entirely.
Returns
- IEnumerable<TResult>
A flattened and projected sequence of results. Each element is yielded, skipped, recursed into, or causes traversal to stop according to the RecursiveSelectControl value returned by
recursionControl.
Type Parameters
TSourceThe type of the source elements.
TResultThe type of the result elements.
Examples
var filtered = rootNodes.RecursiveSelect(
node => node.Children,
(node, index, depth) => node.Name,
node => node.Children.Count > 0
? RecursiveSelectControl.YieldAndRecurse
: RecursiveSelectControl.YieldOnly);
Exceptions
- ArgumentNullException
Thrown if
source,childSelector,selector, orrecursionControlis null.
RecursiveSelect<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TSource>>, Func<TSource, int, TResult>)
Recursively flattens and transforms a hierarchical sequence with index using the provided child selector.
public static IEnumerable<TResult> RecursiveSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, Func<TSource, int, TResult> selector)
Parameters
sourceIEnumerable<TSource>The root sequence to begin recursion from.
childSelectorFunc<TSource, IEnumerable<TSource>>A function that returns child elements for a given element.
selectorFunc<TSource, int, TResult>A function applied to each element with its index.
Returns
- IEnumerable<TResult>
A flattened and projected sequence of results from all elements including children.
Type Parameters
TSourceThe type of the source elements.
TResultThe type of the result elements.
Examples
var indexedNames = rootNodes.RecursiveSelect(
node => node.Children,
(node, index) => $"{index}: {node.Name}");
Exceptions
- ArgumentNullException
Thrown if
source,childSelector, orselectoris null.
RecursiveSelect<TSource, TResult>(IEnumerable<TSource>, Func<TSource, IEnumerable<TSource>>, Func<TSource, TResult>)
Recursively flattens and transforms a hierarchical sequence using the provided child selector and projection.
public static IEnumerable<TResult> RecursiveSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> childSelector, Func<TSource, TResult> selector)
Parameters
sourceIEnumerable<TSource>The root sequence to begin recursion from.
childSelectorFunc<TSource, IEnumerable<TSource>>A function that returns child elements for a given element.
selectorFunc<TSource, TResult>A transform function applied to each element.
Returns
- IEnumerable<TResult>
A flattened and projected sequence of results from all elements including children.
Type Parameters
TSourceThe type of the source elements.
TResultThe type of the projected result elements.
Examples
var names = rootNodes.RecursiveSelect(
node => node.Children,
node => node.Name);
Exceptions
- ArgumentNullException
Thrown if
source,childSelector, orselectoris null.
RunLengthEncode<TSource>(IEnumerable<TSource>)
Compresses each maximal run of consecutive equal elements in the source sequence into a (Value, Count)
tuple, using the default equality comparer.
public static IEnumerable<(TSource Value, int Count)> RunLengthEncode<TSource>(this IEnumerable<TSource> source)
Parameters
sourceIEnumerable<TSource>The source sequence to encode.
Returns
- IEnumerable<(TSource Value, int Count)>
A sequence of
(Value, Count)tuples, one per maximal run of adjacent equal elements insource. The result is empty whensourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Compress each maximal run of adjacent equal characters into a (Value, Count) pair.
foreach (var (value, count) in "aaabbc".RunLengthEncode())
Console.WriteLine($"{value} x {count}");
// => a x 3
// => b x 2
// => c x 1
Remarks
This method uses deferred execution and enumerates the source exactly once in a single forward pass using only O(1) working memory. Equality is compared with Default.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
RunLengthEncode<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>?)
Compresses each maximal run of consecutive equal elements in the source sequence into a (Value, Count)
tuple, using the specified equality comparer.
public static IEnumerable<(TSource Value, int Count)> RunLengthEncode<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource>? comparer)
Parameters
sourceIEnumerable<TSource>The source sequence to encode.
comparerIEqualityComparer<TSource>The comparer used to decide whether adjacent elements belong to the same run, or null to use Default.
Returns
- IEnumerable<(TSource Value, int Count)>
A sequence of
(Value, Count)tuples, one per maximal run of adjacent equal elements insource. The result is empty whensourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
Remarks
This method uses deferred execution and enumerates the source exactly once in a single forward pass using only O(1) working memory. This is adjacent compression, not global counting: a value that reappears after a different value begins a new run.
When bounded over an infinite source, a run that never ends never yields; combine with Take<TSource>(IEnumerable<TSource>, int) only when runs are known to change.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.- OverflowException
Thrown when a single run contains more than MaxValue elements.
Scan<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>)
Emits the running accumulator state after folding each element of the source sequence, starting from a seed.
public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator)
Parameters
sourceIEnumerable<TSource>The source sequence to fold.
seedTAccumulateThe initial accumulator value.
accumulatorFunc<TAccumulate, TSource, TAccumulate>A function that combines the running accumulator with the next element.
Returns
- IEnumerable<TAccumulate>
A sequence containing the accumulator state produced after each source element is folded. The result is empty when
sourceis empty; theseedis never emitted on its own.
Type Parameters
TSourceThe type of elements in the source sequence.
TAccumulateThe type of the accumulator value.
Examples
// Emit the running sum after folding each element (the seed itself is not emitted).
int[] runningTotals = Enumerable.Range(1, 4).Scan(0, (sum, x) => sum + x).ToArray();
// => runningTotals == [ 1, 3, 6, 10 ]
Remarks
This method uses deferred execution. The source sequence is not enumerated until the returned sequence is enumerated, and it is enumerated exactly once in a single forward pass using only O(1) working memory.
This method differs from
Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>):
Aggregate returns only the final accumulator value, whereas this method streams each intermediate state.
Exceptions
- ArgumentNullException
Thrown when
sourceoraccumulatoris null.
Scan<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>)
Emits a projection of the running accumulator state after folding each element of the source sequence, starting from a seed.
public static IEnumerable<TResult> Scan<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to fold.
seedTAccumulateThe initial accumulator value.
accumulatorFunc<TAccumulate, TSource, TAccumulate>A function that combines the running accumulator with the next element.
selectorFunc<TAccumulate, TResult>A projection applied to each running accumulator state before it is emitted.
Returns
- IEnumerable<TResult>
A sequence containing the result of
selectorapplied to the accumulator state produced after each source element is folded. The result is empty whensourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
TAccumulateThe type of the accumulator value.
TResultThe type of the projected result.
Remarks
This method uses deferred execution. The source sequence is not enumerated until the returned sequence is enumerated, and it is enumerated exactly once in a single forward pass using only O(1) working memory.
accumulator and selector are each invoked exactly once per source
element.
Exceptions
- ArgumentNullException
Thrown when
source,accumulator, orselectoris null.
SplitWhen<TSource>(IEnumerable<TSource>, Func<TSource, TSource, bool>)
Splits the source sequence into consecutive chunks, starting a new chunk whenever a boundary predicate over an adjacent pair of elements returns true.
public static IEnumerable<IReadOnlyList<TSource>> SplitWhen<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, bool> shouldSplit)
Parameters
sourceIEnumerable<TSource>The source sequence to split.
shouldSplitFunc<TSource, TSource, bool>A predicate applied to each adjacent pair, receiving the previous and current elements. When it returns true, the current element starts a new chunk.
Returns
- IEnumerable<IReadOnlyList<TSource>>
A sequence of chunks, each a stable snapshot, that together preserve every source element in order. The result is empty when
sourceis empty.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Start a new chunk whenever the value drops (a descending transition).
foreach (var chunk in new[] { 1, 2, 3, 1, 2 }.SplitWhen((previous, current) => previous > current))
Console.WriteLine(string.Join(", ", chunk));
// => 1, 2, 3
// => 1, 2
Remarks
This method uses deferred execution and enumerates the source exactly once in a single forward pass, buffering only the current chunk. This detects transitions between adjacent elements, not separator values.
shouldSplit is invoked exactly once per adjacent pair - that is, count - 1 times.
Each yielded chunk is a stable snapshot and is not modified when the enumerator advances.
When bounded over an infinite source, a chunk whose boundary never occurs never yields; combine with Take<TSource>(IEnumerable<TSource>, int) only when splits are known to occur.
Exceptions
- ArgumentNullException
Thrown when
sourceorshouldSplitis null.
WhereNotNull<TSource>(IEnumerable<TSource?>)
Filters a sequence of nullable value types, yielding the underlying value of each element that has one.
public static IEnumerable<TSource> WhereNotNull<TSource>(this IEnumerable<TSource?> source) where TSource : struct
Parameters
sourceIEnumerable<TSource?>The sequence of Nullable<T> values to filter.
Returns
- IEnumerable<TSource>
A sequence containing the value of every element of
sourcethat is not null, in order.
Type Parameters
TSourceThe value type of the elements.
Remarks
Execution is deferred: source is not enumerated until the returned sequence is iterated,
while the null argument check runs eagerly.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
WhereNotNull<TSource>(IEnumerable<TSource?>)
Filters a sequence of nullable references, yielding only the elements that are not null.
public static IEnumerable<TSource> WhereNotNull<TSource>(this IEnumerable<TSource?> source) where TSource : class
Parameters
sourceIEnumerable<TSource>The sequence of possibly-null references to filter.
Returns
- IEnumerable<TSource>
A sequence containing the non-null elements of
source, in order.
Type Parameters
TSourceThe reference type of the elements.
Remarks
Execution is deferred: source is not enumerated until the returned sequence is iterated,
while the null argument check runs eagerly.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.
Windowed<TSource>(IEnumerable<TSource>, int)
Emits every complete, overlapping fixed-size window over the source sequence, advancing one element at a time.
public static IEnumerable<IReadOnlyList<TSource>> Windowed<TSource>(this IEnumerable<TSource> source, int size)
Parameters
sourceIEnumerable<TSource>The source sequence to slide a window over.
sizeintThe number of elements in each window. Must be greater than 0.
Returns
- IEnumerable<IReadOnlyList<TSource>>
A sequence of windows, each a stable snapshot of exactly
sizeconsecutive elements. The result is empty whensourcecontains fewer thansizeelements.
Type Parameters
TSourceThe type of elements in the source sequence.
Examples
// Slide a window of three across the sequence, advancing one element at a time.
foreach (var window in new[] { 1, 2, 3, 4, 5 }.Windowed(3))
Console.WriteLine(string.Join(", ", window));
// => 1, 2, 3
// => 2, 3, 4
// => 3, 4, 5
Remarks
This method uses deferred execution and enumerates the source exactly once, buffering at most
size elements. Only complete windows are returned, and each is a stable snapshot that is not
modified when the enumerator advances.
This method differs from batching (Chunk<TSource>(IEnumerable<TSource>, int) or Batch<TSource, TResult>(IEnumerable<TSource>, int, Func<TSource, TResult>)): batching returns non-overlapping groups, whereas this method returns overlapping sliding windows.
Exceptions
- ArgumentNullException
Thrown when
sourceis null.- ArgumentOutOfRangeException
Thrown when
sizeis less than 1.
Windowed<TSource, TResult>(IEnumerable<TSource>, int, Func<IReadOnlyList<TSource>, TResult>)
Applies a projection to every complete, overlapping fixed-size window over the source sequence, advancing one element at a time.
public static IEnumerable<TResult> Windowed<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<IReadOnlyList<TSource>, TResult> selector)
Parameters
sourceIEnumerable<TSource>The source sequence to slide a window over.
sizeintThe number of elements in each window. Must be greater than 0.
selectorFunc<IReadOnlyList<TSource>, TResult>A projection applied to each complete window.
Returns
- IEnumerable<TResult>
A sequence containing the result of
selectorapplied to each complete window of exactlysizeconsecutive elements. The result is empty whensourcecontains fewer thansizeelements.
Type Parameters
TSourceThe type of elements in the source sequence.
TResultThe type of the projected result.
Examples
// Compute a rolling sum over each window of two adjacent elements.
int[] rollingSums = new[] { 1, 2, 3, 4 }.Windowed(2, window => window[0] + window[1]).ToArray();
// => rollingSums == [ 3, 5, 7 ]
Remarks
This method uses deferred execution and enumerates the source exactly once, buffering at most
size elements. The first result is not produced until size elements have
been consumed; each subsequent result consumes one additional element.
The window passed to selector is a stable snapshot; retaining it is safe after the
enumerator advances.
Exceptions
- ArgumentNullException
Thrown when
sourceorselectoris null.- ArgumentOutOfRangeException
Thrown when
sizeis less than 1.
ZipLongest<TFirst, TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>)
Zips two sequences into (First, Second) tuples, continuing until both are exhausted and padding the
shorter sequence with default values.
public static IEnumerable<(TFirst First, TSecond Second)> ZipLongest<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second)
Parameters
firstIEnumerable<TFirst>The first sequence to zip.
secondIEnumerable<TSecond>The second sequence to zip.
Returns
- IEnumerable<(TFirst First, TSecond Second)>
A sequence of
(First, Second)tuples whose length equals the longer of the two inputs. Once one sequence is exhausted its side is filled with default until the other is exhausted.
Type Parameters
TFirstThe type of elements in the first sequence.
TSecondThe type of elements in the second sequence.
Examples
// Zip continues to the longer input; the exhausted side is padded with default(T).
foreach (var (number, letter) in new[] { 1, 2, 3 }.ZipLongest(new[] { "a" }))
Console.WriteLine($"{number}:{letter ?? "<null>"}");
// => 1:a
// => 2:<null>
// => 3:<null>
Remarks
This method uses deferred execution and enumerates each sequence exactly once, disposing both enumerators. Unlike Zip<TFirst, TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>), which stops at the shorter input, this method continues until both inputs are exhausted.
This overload pads with default(TFirst) and default(TSecond), which is null for
reference types. Use the overload that accepts explicit defaults to control the padding value.
If one input is infinite, the result is infinite; bound it with Take<TSource>(IEnumerable<TSource>, int) when zipping an unbounded source.
Exceptions
- ArgumentNullException
Thrown when
firstorsecondis null.
ZipLongest<TFirst, TSecond>(IEnumerable<TFirst>, IEnumerable<TSecond>, TFirst, TSecond)
Zips two sequences into (First, Second) tuples, continuing until both are exhausted and padding the
shorter sequence with the supplied default values.
public static IEnumerable<(TFirst First, TSecond Second)> ZipLongest<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, TFirst firstDefault, TSecond secondDefault)
Parameters
firstIEnumerable<TFirst>The first sequence to zip.
secondIEnumerable<TSecond>The second sequence to zip.
firstDefaultTFirstThe value substituted for the first side once
firstis exhausted.secondDefaultTSecondThe value substituted for the second side once
secondis exhausted.
Returns
- IEnumerable<(TFirst First, TSecond Second)>
A sequence of
(First, Second)tuples whose length equals the longer of the two inputs, padding the exhausted side with the corresponding supplied default.
Type Parameters
TFirstThe type of elements in the first sequence.
TSecondThe type of elements in the second sequence.
Examples
// Supply explicit padding values used once a side is exhausted.
var result = new[] { 1 }.ZipLongest(new[] { "a", "b" }, firstDefault: -1, secondDefault: "?").ToArray();
// => result == [ (1, "a"), (-1, "b") ]
Remarks
This method uses deferred execution and enumerates each sequence exactly once, disposing both enumerators.
Exceptions
- ArgumentNullException
Thrown when
firstorsecondis null.
ZipLongest<TFirst, TSecond, TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, TFirst, TSecond, Func<TFirst, TSecond, TResult>)
Zips two sequences with a projection, continuing until both are exhausted and padding the shorter sequence with the supplied default values.
public static IEnumerable<TResult> ZipLongest<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, TFirst firstDefault, TSecond secondDefault, Func<TFirst, TSecond, TResult> selector)
Parameters
firstIEnumerable<TFirst>The first sequence to zip.
secondIEnumerable<TSecond>The second sequence to zip.
firstDefaultTFirstThe value substituted for the first side once
firstis exhausted.secondDefaultTSecondThe value substituted for the second side once
secondis exhausted.selectorFunc<TFirst, TSecond, TResult>A projection applied to each pair of first and second elements.
Returns
- IEnumerable<TResult>
A sequence containing the result of
selectorapplied to each pair, whose length equals the longer of the two inputs, padding the exhausted side with the corresponding supplied default.
Type Parameters
TFirstThe type of elements in the first sequence.
TSecondThe type of elements in the second sequence.
TResultThe type of the projected result.
Remarks
This method uses deferred execution and enumerates each sequence exactly once, disposing both enumerators.
selector is invoked once per emitted element.
Exceptions
- ArgumentNullException
Thrown when
first,second, orselectoris null.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |