// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace System.Linq { public static partial class EnumerableEx { /// /// Generates an enumerable sequence by repeating a source sequence as long as the given loop condition holds. /// /// Result sequence element type. /// Loop condition. /// Sequence to repeat while the condition evaluates true. /// Sequence generated by repeating the given sequence while the condition evaluates to true. public static IEnumerable While(Func condition, IEnumerable source) { if (condition == null) throw new ArgumentNullException(nameof(condition)); if (source == null) throw new ArgumentNullException(nameof(source)); return WhileCore(condition, source).Concat(); } static IEnumerable> WhileCore(Func condition, IEnumerable source) { while (condition()) yield return source; } /// /// Returns an enumerable sequence based on the evaluation result of the given condition. /// /// Result sequence element type. /// Condition to evaluate. /// Sequence to return in case the condition evaluates true. /// Sequence to return in case the condition evaluates false. /// Either of the two input sequences based on the result of evaluating the condition. public static IEnumerable If(Func condition, IEnumerable thenSource, IEnumerable elseSource) { if (condition == null) throw new ArgumentNullException(nameof(condition)); if (thenSource == null) throw new ArgumentNullException(nameof(thenSource)); if (elseSource == null) throw new ArgumentNullException(nameof(elseSource)); return EnumerableEx.Defer(() => condition() ? thenSource : elseSource); } /// /// Returns an enumerable sequence if the evaluation result of the given condition is true, otherwise returns an empty sequence. /// /// Result sequence element type. /// Condition to evaluate. /// Sequence to return in case the condition evaluates true. /// The given input sequence if the condition evaluates true; otherwise, an empty sequence. public static IEnumerable If(Func condition, IEnumerable thenSource) { if (condition == null) throw new ArgumentNullException(nameof(condition)); if (thenSource == null) throw new ArgumentNullException(nameof(thenSource)); return EnumerableEx.Defer(() => condition() ? thenSource : Enumerable.Empty()); } /// /// Generates an enumerable sequence by repeating a source sequence as long as the given loop postcondition holds. /// /// Result sequence element type. /// Source sequence to repeat while the condition evaluates true. /// Loop condition. /// Sequence generated by repeating the given sequence until the condition evaluates to false. public static IEnumerable DoWhile(this IEnumerable source, Func condition) { if (source == null) throw new ArgumentNullException(nameof(source)); if (condition == null) throw new ArgumentNullException(nameof(condition)); return source.Concat(While(condition, source)); } /// /// Returns a sequence from a dictionary based on the result of evaluating a selector function. /// /// Type of the selector value. /// Result sequence element type. /// Selector function used to pick a sequence from the given sources. /// Dictionary mapping selector values onto resulting sequences. /// The source sequence corresponding with the evaluated selector value; otherwise, an empty sequence. public static IEnumerable Case(Func selector, IDictionary> sources) { if (selector == null) throw new ArgumentNullException(nameof(selector)); if (sources == null) throw new ArgumentNullException(nameof(sources)); return Case(selector, sources, Enumerable.Empty()); } /// /// Returns a sequence from a dictionary based on the result of evaluating a selector function, also specifying a default sequence. /// /// Type of the selector value. /// Result sequence element type. /// Selector function used to pick a sequence from the given sources. /// Dictionary mapping selector values onto resulting sequences. /// Default sequence to return in case there's no corresponding source for the computed selector value. /// The source sequence corresponding with the evaluated selector value; otherwise, the default source. public static IEnumerable Case(Func selector, IDictionary> sources, IEnumerable defaultSource) { if (selector == null) throw new ArgumentNullException(nameof(selector)); if (sources == null) throw new ArgumentNullException(nameof(sources)); if (defaultSource == null) throw new ArgumentNullException(nameof(defaultSource)); return EnumerableEx.Defer(() => { IEnumerable result; if (!sources.TryGetValue(selector(), out result)) result = defaultSource; return result; }); } /// /// Generates a sequence by enumerating a source sequence, mapping its elements on result sequences, and concatenating those sequences. /// /// Source sequence element type. /// Result sequence element type. /// Source sequence. /// Result selector to evaluate for each iteration over the source. /// Sequence concatenating the inner sequences that result from evaluating the result selector on elements from the source. public static IEnumerable For(IEnumerable source, Func> resultSelector) { if (source == null) throw new ArgumentNullException(nameof(source)); if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); return ForCore(source, resultSelector).Concat(); } static IEnumerable> ForCore(IEnumerable source, Func> resultSelector) { return source.Select(resultSelector); } } }