// (c) Copyright Microsoft Corporation. // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993] for details. // All other rights reserved. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; namespace System.Windows.Controls { /// /// This class contains general purpose functions to manipulate the generic /// IEnumerable type. /// internal static class EnumerableFunctions { /////// /////// Applies a function to an accumulated value and an item in the /////// sequence and yields the result as the accumulated value. /////// /////// The type of the sequence. /////// The sequence to scan. /////// The function applied to the accumulator and the /////// current item. /////// A sequence of computed values. ////public static IEnumerable Scan(this IEnumerable that, Func func) ////{ //// IEnumerator enumerator = that.GetEnumerator(); //// if (!enumerator.MoveNext()) //// { //// yield break; //// } //// T acc = enumerator.Current; //// yield return acc; //// while (enumerator.MoveNext()) //// { //// acc = func(acc, enumerator.Current); //// yield return acc; //// } ////} /// /// Applies a function to an accumulated value and an item in the /// sequence and yields the result as the accumulated value. /// /// The type of the input sequence. /// The type of the initial value. /// The sequence to scan. /// The function applied to the accumulator and the /// current item. /// The initial value in the output sequence. /// /// A sequence of computed values. public static IEnumerable Scan(this IEnumerable that, Func func, R initialValue) { R acc = initialValue; yield return acc; IEnumerator enumerator = that.GetEnumerator(); while (enumerator.MoveNext()) { acc = func(acc, enumerator.Current); yield return acc; } } /// /// Accepts two sequences and applies a function to the corresponding /// values in the two sequences. /// /// The type of the first sequence. /// The type of the second sequence. /// The return type of the function. /// The first sequence. /// The second sequence. /// The function to apply to the corresponding values /// from the two sequences. /// A sequence of transformed values from both sequences. public static IEnumerable Zip(IEnumerable enumerable0, IEnumerable enumerable1, Func func) { IEnumerator enumerator0 = enumerable0.GetEnumerator(); IEnumerator enumerator1 = enumerable1.GetEnumerator(); while (enumerator0.MoveNext() && enumerator1.MoveNext()) { yield return func(enumerator0.Current, enumerator1.Current); } } /// /// Returns the index of an item in a sequence. /// /// The type of the sequence. /// The sequence. /// The item in the sequence. /// The index of an item in a sequence. public static int? IndexOf(this IEnumerable that, T item) { IEnumerator enumerator = that.GetEnumerator(); int index = 0; while (enumerator.MoveNext()) { if (object.ReferenceEquals(enumerator.Current, item)) { return index; } index++; } return null; } /// /// Returns a stream of weighted values based on a percentage. /// /// A sequence of values. /// The percentage of values. /// A sequence of percentages. public static IEnumerable GetWeightedValues(this IEnumerable values, double percent) { double total = values.Sum(); if (total == 0) { return values.Select(_ => 0.0); } return EnumerableFunctions .Zip( values.Scan((acc, current) => acc + current, 0.0), values, (acc, current) => Tuple.Create(acc, current)) .Select(tuple => Tuple.Create(tuple.First / total, tuple.Second / total)) .Select(tuple => { double accumulated = tuple.First; double current = tuple.Second; if (percent > accumulated && accumulated + current > percent) { return (percent - accumulated) * total; } else if (percent <= accumulated) { return 0.0; } else { return 1.0; } }); } } }