// (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;
}
});
}
}
}