Die .Where()-Funktion ist richtig klasse und ich setze sie in meinem Code oft ein.
Manchmal brauche ich aber beides, das Resultat von .Where() und den Rest, der übrig bleibt.
Deshalb habe ich mir ein .Split()-Funktion geschrieben.
Da ich nicht auf die Delayed Execution von Linq angewiesen bin, benutze ich die performantere .Split()-Funktion.
Wer aber möchte, kann die .SplitDelayed()-Funktion benutzen, die erst ausgeführt wird (wie bei allen Linq-Sachen), sobald ein Enumerator angefordert wird (z.B. bei foreach).
public static class LinqHelper
{
/// <summary>
/// Splits a collection into two lists based on the given true/false evaluation.
///
/// Note: This method resolves the query at once for performance considerations.
/// It does not use delayed execution!
/// </summary>
/// <typeparam name="T">the type of the list items</typeparam>
/// <param name="inList">the original list</param>
/// <param name="predicate">the function delegate to the evaluator</param>
/// <param name="trueList">the true results</param>
/// <param name="falseList">the false results</param>
public static void Split<T>(this IEnumerable<T> inList
, Func<T, Boolean> predicate
, out IEnumerable<T> trueList
, out IEnumerable<T> falseList)
{
//The .ToList() is deliberately here
//otherwise the predicate would always be checked twice.
//First when the user of the method iterates over the trueList
//Second when the user of the method iterates over the falseList
trueList = inList.Where(predicate).ToList();
falseList = inList.Except(trueList).ToList();
}
/// <summary>
/// Splits a collection into two lists based on the given true/false evaluation
/// </summary>
/// <typeparam name="T">the type of the list items</typeparam>
/// <param name="inList">the original list</param>
/// <param name="predicate">the function delegate to the evaluator</param>
/// <param name="trueList">the true results</param>
/// <param name="falseList">the false results</param>
public static void SplitDelayed<T>(this IEnumerable<T> inList
, Func<T, Boolean> predicate
, out IEnumerable<T> trueList
, out IEnumerable<T> falseList)
{
trueList = inList.Where(predicate);
falseList = inList.Except(trueList);
}
}
static class Demo
{
static void Main()
{
SplitDemo();
}
private static void SplitDemo()
{
List<Int32> list;
IEnumerable<Int32> odds;
IEnumerable<Int32> evens;
const Int32 Max = 10000000;
list = new List<Int32>(Max);
for (Int32 i = 1; i <= Max; i++)
{
list.Add(i);
}
list.SplitDelayed(number => ((number % 2) == 0), out evens, out odds);
Output(odds, evens);
Console.WriteLine();
Output(odds.ToList(), evens.ToList());
Console.WriteLine();
list.Split(number => ((number % 2) == 0), out evens, out odds);
Output(odds, evens);
Console.WriteLine();
Output(odds.ToList(), evens.ToList());
Console.WriteLine();
Console.WriteLine("Done.");
Console.ReadLine();
}
private static void Output(IEnumerable<Int32> odds
, IEnumerable<Int32> evens)
{
for (Int32 i = 0; i < 10; i++)
{
DateTime start;
DateTime end;
TimeSpan span;
start = DateTime.UtcNow;
foreach (Int32 even in evens)
{ }
foreach (Int32 odd in odds)
{ }
end = DateTime.UtcNow;
span = new TimeSpan(end.Ticks - start.Ticks);
Console.WriteLine(span.Seconds
+ "." + span.Milliseconds.ToString("000"));
}
}
}
4 Kommentare zum Snippet