// (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.DataVisualization
{
///
/// This class contains general purpose functions to manipulate the generic
/// IEnumerable type.
///
internal static class EnumerableFunctions
{
///
/// Attempts to cast IEnumerable to a list in order to retrieve a count
/// in order one. It attempts to cast fail the sequence is enumerated.
///
/// The sequence.
/// The number of elements in the sequence.
public static int FastCount(this IEnumerable that)
{
IList list = that as IList;
if (list != null)
{
return list.Count;
}
return that.CastWrapper().Count();
}
///
/// Returns the minimum value in the stream based on the result of a
/// project function.
///
/// The stream type.
/// The stream.
/// The function that transforms the
/// item.
/// The minimum value or null.
public static T MinOrNull(this IEnumerable that, Func projectionFunction)
where T : class
{
IComparable result = null;
T minimum = default(T);
if (!that.Any())
{
return minimum;
}
minimum = that.First();
result = projectionFunction(minimum);
foreach (T item in that.Skip(1))
{
IComparable currentResult = projectionFunction(item);
if (result.CompareTo(currentResult) > 0)
{
result = currentResult;
minimum = item;
}
}
return minimum;
}
///
/// Returns the sum of all values in the sequence or the default value.
///
/// The stream.
/// The sum of all values or the default value.
public static double SumOrDefault(this IEnumerable that)
{
if (!that.Any())
{
return 0.0;
}
else
{
return that.Sum();
}
}
///
/// Returns the maximum value in the stream based on the result of a
/// project function.
///
/// The stream type.
/// The stream.
/// The function that transforms the
/// item.
/// The maximum value or null.
public static T MaxOrNull(this IEnumerable that, Func projectionFunction)
where T : class
{
IComparable result = null;
T maximum = default(T);
if (!that.Any())
{
return maximum;
}
maximum = that.First();
result = projectionFunction(maximum);
foreach (T item in that.Skip(1))
{
IComparable currentResult = projectionFunction(item);
if (result.CompareTo(currentResult) < 0)
{
result = currentResult;
maximum = item;
}
}
return maximum;
}
///
/// 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);
}
}
///
/// Creates a sequence of values by accepting an initial value, an
/// iteration function, and apply the iteration function recursively.
///
/// The type of the sequence.
/// The initial value.
/// The function to apply to the value.
///
/// A sequence of the iterated values.
public static IEnumerable Iterate(T value, Func nextFunction)
{
yield return value;
while (true)
{
value = nextFunction(value);
yield return value;
}
}
///
/// Returns the index of an item in a sequence.
///
/// The sequence.
/// The item to search for.
/// The index of the item or -1 if not found.
public static int IndexOf(this IEnumerable that, object value)
{
int index = 0;
foreach (object item in that)
{
if (object.ReferenceEquals(value, item) || value.Equals(item))
{
return index;
}
index++;
}
return -1;
}
///
/// Executes an action for each item and a sequence, passing in the
/// index of that item to the action procedure.
///
/// The type of the sequence.
/// The sequence.
/// A function that accepts a sequence item and its
/// index in the sequence.
public static void ForEachWithIndex(this IEnumerable that, Action action)
{
int index = 0;
foreach (T item in that)
{
action(item, index);
index++;
}
}
///
/// Returns the maximum value or null if sequence is empty.
///
/// The type of the sequence.
/// The sequence to retrieve the maximum value from.
///
/// The maximum value or null.
public static T? MaxOrNullable(this IEnumerable that)
where T : struct, IComparable
{
if (!that.Any())
{
return null;
}
return that.Max();
}
///
/// Returns the minimum value or null if sequence is empty.
///
/// The type of the sequence.
/// The sequence to retrieve the minimum value from.
///
/// The minimum value or null.
public static T? MinOrNullable(this IEnumerable that)
where T : struct, IComparable
{
if (!that.Any())
{
return null;
}
return that.Min();
}
///
/// Attempts to retrieve an element at an index by testing whether a
/// sequence is randomly accessible. If not, performance degrades to a
/// linear search.
///
/// The type of the elements in the sequence.
/// The sequence.
/// The index of the element in the sequence.
/// The element at the given index.
public static T FastElementAt(this IEnumerable that, int index)
{
{
IList list = that as IList;
if (list != null)
{
return list[index];
}
}
{
IList list = that as IList;
if (list != null)
{
return (T) list[index];
}
}
return that.CastWrapper().ElementAt(index);
}
///
/// Applies an accumulator function over a sequence and returns each intermediate result.
///
/// Type of elements in source sequence.
/// Type of elements in result sequence.
/// Sequence to scan.
/// Initial accumulator value.
/// Function used to generate the result sequence.
/// Sequence of intermediate results.
public static IEnumerable Scan(this IEnumerable that, S seed, Func accumulator)
{
S value = seed;
yield return seed;
foreach (T t in that)
{
value = accumulator(value, t);
yield return value;
}
yield break;
}
///
/// Converts the elements of an System.Collections.IEnumerable to the specified type.
///
///
/// A wrapper for the Enumerable.Cast(T) method that works around a limitation on some platforms.
///
/// The type to convert the elements of source to.
/// The System.Collections.IEnumerable that contains the elements to be converted.
///
/// An System.Collections.Generic.IEnumerable(T) that contains each element of the source sequence converted to the specified type.
///
public static IEnumerable CastWrapper(this IEnumerable source)
{
#if SILVERLIGHT
// Certain flavors of this platform have a bug which causes Cast to raise an exception incorrectly.
// Work around that by using the more general OfType method instead for no loss of functionality.
return source.OfType();
#else
// No issues on this platform - call directly through to Cast
return source.Cast();
#endif
}
}
}