Feedback

C# - Linq: Die Guten ins Töpfchen, die Schlechten ...

Veröffentlicht von am 27.11.2014
(2 Bewertungen)
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"));
        }
    }
}
Abgelegt unter where, except, split, linq.

4 Kommentare zum Snippet

Koopakiller schrieb am 27.11.2014:
Sicherlich oftmals eine Vereinfachung. Du solltest das mit dem ToList allerdings auch in die XML Doku hinein schreiben.
Grundsätzlich kann man die verzögerte Ausführung nämlich von fast allen LINQ Methoden erwarten, sodass man eine Abweichung wenigstens erwähnen sollte.
DJ Doena schrieb am 28.11.2014:
@Koopakiller: XML Kommentar angepasst
Jan Welker schrieb am 28.11.2014:
Gute Idee! Die Anforderung hatte ich auch schon einige mal, hab mir aber nie was generisches gebaut.
Koopakiller schrieb am 28.11.2014:
Da gab es jetzt auch die 5 Sterne :)
 

Logge dich ein, um hier zu kommentieren!