Table of Contents

IEnumerableExtensions Class

Definition

Namespace
Bodu.Collections.Generic.Extensions
Assembly
Bodu.Core.dll
Package
Bodu.Core 1.0.1
Source
IEnumerableExtensions.Aggregate.cs

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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed TAccumulate

The initial accumulator value.

func Func<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

TSource

The type of the elements contained in the sequence.

TAccumulate

The 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 source or func is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed TAccumulate

The initial accumulator value.

func Func<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.

resultSelector Func<TAccumulate, TResult>

A function that transforms the final accumulator value into the returned result.

Returns

TResult

The value produced by applying resultSelector to the final accumulator value.

Type Parameters

TSource

The type of the elements contained in the sequence.

TAccumulate

The type of the accumulator value.

TResult

The type of the resulting value.

Remarks

If source is empty, resultSelector is applied to seed.

Exceptions

ArgumentNullException

Thrown when source, func, or resultSelector is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

func1 Func<T1, TSource, int, T1>

An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.

func2 Func<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

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The 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, or func2 is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

func1 Func<T1, TSource, T1>

An accumulator function invoked on each element for the first accumulator.

func2 Func<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

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The 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, or func2 is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

func1 Func<T1, TSource, int, T1>

An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.

func2 Func<T2, TSource, int, T2>

An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.

resultSelector Func<T1, T2, TResult>

A function that transforms the final accumulator values into the returned result.

Returns

TResult

The value produced by applying resultSelector to the final accumulator values.

Type Parameters

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

TResult

The type of the resulting value.

Exceptions

ArgumentNullException

Thrown when source, func1, func2, or resultSelector is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

func1 Func<T1, TSource, T1>

An accumulator function invoked on each element for the first accumulator.

func2 Func<T2, TSource, T2>

An accumulator function invoked on each element for the second accumulator.

resultSelector Func<T1, T2, TResult>

A function that transforms the final accumulator values into the returned result.

Returns

TResult

The value produced by applying resultSelector to the final accumulator values.

Type Parameters

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

TResult

The type of the resulting value.

Exceptions

ArgumentNullException

Thrown when source, func1, func2, or resultSelector is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

seed3 T3

The initial value of the third accumulator.

func1 Func<T1, TSource, int, T1>

An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.

func2 Func<T2, TSource, int, T2>

An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.

func3 Func<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

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

T3

The 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, or func3 is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

seed3 T3

The initial value of the third accumulator.

func1 Func<T1, TSource, T1>

An accumulator function invoked on each element for the first accumulator.

func2 Func<T2, TSource, T2>

An accumulator function invoked on each element for the second accumulator.

func3 Func<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

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

T3

The 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, or func3 is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

seed3 T3

The initial value of the third accumulator.

func1 Func<T1, TSource, int, T1>

An accumulator function invoked on each element for the first accumulator; receives the element's index as its third argument.

func2 Func<T2, TSource, int, T2>

An accumulator function invoked on each element for the second accumulator; receives the element's index as its third argument.

func3 Func<T3, TSource, int, T3>

An accumulator function invoked on each element for the third accumulator; receives the element's index as its third argument.

resultSelector Func<T1, T2, T3, TResult>

A function that transforms the final accumulator values into the returned result.

Returns

TResult

The value produced by applying resultSelector to the final accumulator values.

Type Parameters

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

T3

The type of the third accumulator value.

TResult

The type of the resulting value.

Exceptions

ArgumentNullException

Thrown when source, func1, func2, func3, or resultSelector is 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

source IEnumerable<TSource>

An IEnumerable<T> to aggregate over.

seed1 T1

The initial value of the first accumulator.

seed2 T2

The initial value of the second accumulator.

seed3 T3

The initial value of the third accumulator.

func1 Func<T1, TSource, T1>

An accumulator function invoked on each element for the first accumulator.

func2 Func<T2, TSource, T2>

An accumulator function invoked on each element for the second accumulator.

func3 Func<T3, TSource, T3>

An accumulator function invoked on each element for the third accumulator.

resultSelector Func<T1, T2, T3, TResult>

A function that transforms the final accumulator values into the returned result.

Returns

TResult

The value produced by applying resultSelector to the final accumulator values.

Type Parameters

TSource

The type of the elements contained in the sequence.

T1

The type of the first accumulator value.

T2

The type of the second accumulator value.

T3

The type of the third accumulator value.

TResult

The type of the resulting value.

Exceptions

ArgumentNullException

Thrown when source, func1, func2, func3, or resultSelector is 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

source IEnumerable<TSource>

The source sequence to batch.

size int

The 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

TSource

The 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 source is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<TSource>

The source sequence to batch.

size int

The maximum number of items per batch.

selector Func<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

TSource

The type of elements in the source sequence.

TResult

The 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 source or selector is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<TSource>

The source sequence to batch.

size int

The size of each batch. Must be greater than 0.

selector Func<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 size transformed elements.

Type Parameters

TSource

The type of elements in the source sequence.

TResult

The type of result elements.

Remarks

This method uses deferred execution. The projection and batching occur only during enumeration.

Exceptions

ArgumentNullException

Thrown when source or selector is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<TSource>

The source sequence to batch.

size int

The size of each batch. Must be greater than 0.

selector Func<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 size transformed elements.

Type Parameters

TSource

The type of elements in the source sequence.

TResult

The 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 source or selector is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<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

T

The 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

source is 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

first IEnumerable<TFirst>

The first sequence, whose elements drive the outer loop of the product.

second IEnumerable<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

TFirst

The type of elements in the first sequence.

TSecond

The 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 first or second is 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

first IEnumerable<TFirst>

The first sequence, whose elements drive the outer loop of the product.

second IEnumerable<TSecond>

The second sequence, whose elements drive the inner loop of the product.

resultSelector Func<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 resultSelector applied 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

TFirst

The type of elements in the first sequence.

TSecond

The type of elements in the second sequence.

TResult

The 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, or resultSelector is 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

source IEnumerable<TSource>

The source sequence to group.

keySelector Func<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 where Items is a stable snapshot of a maximal run of adjacent elements sharing Key. The result is empty when source is empty.

Type Parameters

TSource

The type of elements in the source sequence.

TKey

The 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 source or keySelector is 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

source IEnumerable<TSource>

The source sequence to group.

keySelector Func<TSource, TKey>

A function that produces the grouping key for each element.

comparer IEqualityComparer<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 where Items is a stable snapshot of a maximal run of adjacent elements sharing Key. The result is empty when source is empty.

Type Parameters

TSource

The type of elements in the source sequence.

TKey

The 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 source or keySelector is 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

source IEnumerable<TSource>

The source sequence to draw combinations from.

size int

The 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 size elements in source order. When size is 0 the result contains a single empty row; when size exceeds the source count the result is empty.

Type Parameters

TSource

The 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 source is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<T>

The source sequence to search.

items IEnumerable<T>

The items to verify against the source sequence.

comparer IEqualityComparer<T>

An optional equality comparer to use; if null, the default comparer is used.

Returns

bool

true if all items exist in source; otherwise, false.

Type Parameters

T

The 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 source or items is 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

source IEnumerable<T>

The source sequence to search.

items IEnumerable<T>

The items to locate within the source sequence.

comparer IEqualityComparer<T>

An optional equality comparer to use for element comparisons; if null, the default comparer is used.

Returns

bool

true if any item in items exists in source; otherwise, false.

Type Parameters

T

The 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 source or items is 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

source IEnumerable<TSource>

The sequence whose elements are passed to action.

action Action<TSource>

The delegate invoked for each element.

Type Parameters

TSource

The 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 source or action is 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

source IEnumerable<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

TSource

The 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 source is 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

first IEnumerable<TSource>

The first sequence, which contributes the first element of each round.

others IEnumerable<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 first and continuing through others in order. The result length is the sum of the input lengths.

Type Parameters

TSource

The 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 first or others is null.

ArgumentException

Thrown when others contains 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

source IEnumerable<TSource>

The sequence to test. May be null.

Returns

bool

true when source is null or yields no elements; otherwise, false.

Type Parameters

TSource

The 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

source IEnumerable<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 in source. The result is empty when source contains fewer than two elements.

Type Parameters

TSource

The 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 source is 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

source IEnumerable<TSource>

The source sequence to pair.

selector Func<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 selector applied to every adjacent pair of elements in source. The result is empty when source contains fewer than two elements.

Type Parameters

TSource

The type of elements in the source sequence.

TResult

The 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 source or selector is 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

source IEnumerable<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

TSource

The 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 source is 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

source IEnumerable<TSource>

The source sequence to permute.

size int

The 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 size elements. When size is 0 the result contains a single empty row; when size exceeds the source count the result is empty.

Type Parameters

TSource

The 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 source is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<T>

The sequence to randomize.

mode RandomizationMode

The randomization strategy to apply.

rng IRandomGenerator

The random number generator to use.

count int?

The number of items to return; returns all items when null.

Returns

IEnumerable<T>

A randomized sequence of T.

Type Parameters

T

The 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 source or rng is null.

ArgumentOutOfRangeException

Thrown if count is negative, exceeds the number of available elements, or if mode is not a defined RandomizationMode value.

ArgumentException

Thrown if count is null and mode requires 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

source IEnumerable<TSource>

The root sequence to begin recursion from.

childSelector Func<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

TSource

The type of the elements in the sequence.

Examples

var allNodes = rootNodes.RecursiveSelect(node => node.Children);

Exceptions

ArgumentNullException

Thrown if source or childSelector is 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

source IEnumerable<TSource>

The root sequence to begin recursion from.

childSelector Func<TSource, IEnumerable<TSource>>

A function that returns child elements for a given element.

selector Func<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

TSource

The type of the source elements.

TResult

The 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, or selector is 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

source IEnumerable<TSource>

The root sequence to begin recursion from.

childSelector Func<TSource, IEnumerable<TSource>>

A function that returns child elements for a given element.

selector Func<TSource, int, int, TResult>

A transform function applied to each element with index and depth.

recursionControl Func<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

TSource

The type of the source elements.

TResult

The 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, or recursionControl is 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

source IEnumerable<TSource>

The root sequence to begin recursion from.

childSelector Func<TSource, IEnumerable<TSource>>

A function that returns child elements for a given element.

selector Func<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

TSource

The type of the source elements.

TResult

The type of the result elements.

Examples

var indexedNames = rootNodes.RecursiveSelect(
    node => node.Children,
    (node, index) => $"{index}: {node.Name}");

Exceptions

ArgumentNullException

Thrown if source, childSelector, or selector is 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

source IEnumerable<TSource>

The root sequence to begin recursion from.

childSelector Func<TSource, IEnumerable<TSource>>

A function that returns child elements for a given element.

selector Func<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

TSource

The type of the source elements.

TResult

The type of the projected result elements.

Examples

var names = rootNodes.RecursiveSelect(
    node => node.Children,
    node => node.Name);

Exceptions

ArgumentNullException

Thrown if source, childSelector, or selector is 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

source IEnumerable<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 in source. The result is empty when source is empty.

Type Parameters

TSource

The 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 source is 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

source IEnumerable<TSource>

The source sequence to encode.

comparer IEqualityComparer<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 in source. The result is empty when source is empty.

Type Parameters

TSource

The 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 source is 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

source IEnumerable<TSource>

The source sequence to fold.

seed TAccumulate

The initial accumulator value.

accumulator Func<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 source is empty; the seed is never emitted on its own.

Type Parameters

TSource

The type of elements in the source sequence.

TAccumulate

The 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 source or accumulator is 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

source IEnumerable<TSource>

The source sequence to fold.

seed TAccumulate

The initial accumulator value.

accumulator Func<TAccumulate, TSource, TAccumulate>

A function that combines the running accumulator with the next element.

selector Func<TAccumulate, TResult>

A projection applied to each running accumulator state before it is emitted.

Returns

IEnumerable<TResult>

A sequence containing the result of selector applied to the accumulator state produced after each source element is folded. The result is empty when source is empty.

Type Parameters

TSource

The type of elements in the source sequence.

TAccumulate

The type of the accumulator value.

TResult

The 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, or selector is 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

source IEnumerable<TSource>

The source sequence to split.

shouldSplit Func<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 source is empty.

Type Parameters

TSource

The 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 source or shouldSplit is 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

source IEnumerable<TSource?>

The sequence of Nullable<T> values to filter.

Returns

IEnumerable<TSource>

A sequence containing the value of every element of source that is not null, in order.

Type Parameters

TSource

The 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 source is 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

source IEnumerable<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

TSource

The 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 source is 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

source IEnumerable<TSource>

The source sequence to slide a window over.

size int

The 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 size consecutive elements. The result is empty when source contains fewer than size elements.

Type Parameters

TSource

The 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 source is null.

ArgumentOutOfRangeException

Thrown when size is 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

source IEnumerable<TSource>

The source sequence to slide a window over.

size int

The number of elements in each window. Must be greater than 0.

selector Func<IReadOnlyList<TSource>, TResult>

A projection applied to each complete window.

Returns

IEnumerable<TResult>

A sequence containing the result of selector applied to each complete window of exactly size consecutive elements. The result is empty when source contains fewer than size elements.

Type Parameters

TSource

The type of elements in the source sequence.

TResult

The 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 source or selector is null.

ArgumentOutOfRangeException

Thrown when size is 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

first IEnumerable<TFirst>

The first sequence to zip.

second IEnumerable<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

TFirst

The type of elements in the first sequence.

TSecond

The 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 first or second is 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

first IEnumerable<TFirst>

The first sequence to zip.

second IEnumerable<TSecond>

The second sequence to zip.

firstDefault TFirst

The value substituted for the first side once first is exhausted.

secondDefault TSecond

The value substituted for the second side once second is 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

TFirst

The type of elements in the first sequence.

TSecond

The 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 first or second is 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

first IEnumerable<TFirst>

The first sequence to zip.

second IEnumerable<TSecond>

The second sequence to zip.

firstDefault TFirst

The value substituted for the first side once first is exhausted.

secondDefault TSecond

The value substituted for the second side once second is exhausted.

selector Func<TFirst, TSecond, TResult>

A projection applied to each pair of first and second elements.

Returns

IEnumerable<TResult>

A sequence containing the result of selector applied to each pair, whose length equals the longer of the two inputs, padding the exhausted side with the corresponding supplied default.

Type Parameters

TFirst

The type of elements in the first sequence.

TSecond

The type of elements in the second sequence.

TResult

The 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, or selector is null.

Applies to

ProductVersions
.NET8, 10