Feedback

Items zweier Listen vergleichen

Sprache: C#

Diese Erweiterungsmethode vergleicht zwei auflistungen auf Gleichheit. Dabei werden jedoch nicht die Listeninstanzen sondern die Elemente in den Listen verglichen. Auf wunsch wird die Reihenfolge der Elemente ignoriert. [b]Benötigte Namespaces[/b] System System.Collections.Generic System.Linq [b]Hinweis[/b] Die LINQ Methode SequenceEqual erziehlt ein ähnliches Ergebnis. Jedoch erlaubt die Methode keine Angabe, ob die Anordnung der Elemente beachtet werden soll. [b]Testanwendung[/b] [code]string[] a1 = { "a", "b", "c", "d", "e" }; string[] a2 = { "a", "b", "c", "d", "e" }; string[] a3 = { "a", "b", "c", "e", "d" }; string[] a4 = { "a", "b", "c", "d" }; string[] a5 = { "a", "a", "a", "b" ,"c"}; string[] a6 = { "a", "a", "b", "b" }; string[] a7 = { "a", "a", "a", "b" }; bool flag = true;//Bitte ändern um den 3. Parameter zu testen Console.WriteLine(a1.AreItemsEqual(a2, (x, y) => x == y, flag));//immer true Console.WriteLine(a1.AreItemsEqual(a3, (x, y) => x == y, flag));//true wenn flag = true Console.WriteLine(a1.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a1.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a1.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.WriteLine(a1.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a2.AreItemsEqual(a1, (x, y) => x == y, flag));//immer true Console.WriteLine(a2.AreItemsEqual(a3, (x, y) => x == y, flag));//true wenn flag = true Console.WriteLine(a2.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a2.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a2.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.WriteLine(a2.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a3.AreItemsEqual(a1, (x, y) => x == y, flag));//true wenn flag = true Console.WriteLine(a3.AreItemsEqual(a2, (x, y) => x == y, flag));//true wenn flag = true Console.WriteLine(a3.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a3.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a3.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.WriteLine(a3.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a4.AreItemsEqual(a1, (x, y) => x == y, flag)); Console.WriteLine(a4.AreItemsEqual(a2, (x, y) => x == y, flag)); Console.WriteLine(a4.AreItemsEqual(a3, (x, y) => x == y, flag)); Console.WriteLine(a4.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a4.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.WriteLine(a4.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a5.AreItemsEqual(a1, (x, y) => x == y, flag)); Console.WriteLine(a5.AreItemsEqual(a2, (x, y) => x == y, flag)); Console.WriteLine(a5.AreItemsEqual(a3, (x, y) => x == y, flag)); Console.WriteLine(a5.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a5.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.WriteLine(a5.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a6.AreItemsEqual(a1, (x, y) => x == y, flag)); Console.WriteLine(a6.AreItemsEqual(a2, (x, y) => x == y, flag)); Console.WriteLine(a6.AreItemsEqual(a3, (x, y) => x == y, flag)); Console.WriteLine(a6.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a6.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a6.AreItemsEqual(a7, (x, y) => x == y, flag)); Console.WriteLine(); Console.WriteLine(a7.AreItemsEqual(a1, (x, y) => x == y, flag)); Console.WriteLine(a7.AreItemsEqual(a2, (x, y) => x == y, flag)); Console.WriteLine(a7.AreItemsEqual(a3, (x, y) => x == y, flag)); Console.WriteLine(a7.AreItemsEqual(a4, (x, y) => x == y, flag)); Console.WriteLine(a7.AreItemsEqual(a5, (x, y) => x == y, flag)); Console.WriteLine(a7.AreItemsEqual(a6, (x, y) => x == y, flag)); Console.ReadKey();[/code]
/// <summary>
/// Überprüft ob die Elemente zweier Listen identisch sind.
/// </summary>
/// <typeparam name="T">Der Typ von dem die Elemente der Liste sind.</typeparam>
/// <param name="source">Die erste Liste.</param>
/// <param name="other">Die zweite Liste.</param>
/// <param name="equal">Eine Funktion zum überprüfen auf Gleichheit.</param>
/// <param name="ignoreOrder"><c>True</c>, wenn die Reihenfolge der Elemente ignoriert werden soll; andernfalls <c>false</c>.</param>
/// <returns><c>true</c>, wenn <paramref name="source"/> und <paramref name="other"/> in den Elementen übereinstimmen; andernfalls <c>false</c>.</returns>
public static bool AreItemsEqual<T>(this IEnumerable<T> source, IEnumerable<T> other, Func<T, T, bool> equal, bool ignoreOrder)
{
    if (source == null) throw new ArgumentNullException("source");
    if (other == null) throw new ArgumentNullException("other");
    if (equal == null) throw new ArgumentNullException("equal");

    using (var enu1 = source.GetEnumerator())
    {
        using (var enu2 = other.GetEnumerator())
        {
            bool b1 = true, b2 = true;
            if (ignoreOrder)
            {
                foreach (var dist in source.Distinct())
                    if (source.Count(x => equal(x, dist)) != other.Count(x => equal(x, dist)))
                        return false;

                while ((b1 = enu1.MoveNext()) & (b2 = enu2.MoveNext())) { }
            }
            else
                while ((b1 = enu1.MoveNext()) & (b2 = enu2.MoveNext()))
                {
                    if (!equal(enu1.Current, enu2.Current))
                        return false;
                }

            if (b1 != b2)
                return false;//one at end, the other not
            else
                return true;
        }
    }
}
/// <summary>
/// Überprüft ob die Elemente zweier Listen identisch sind.
/// </summary>
/// <typeparam name="T">Der Typ von dem die Elemente der Liste sind.</typeparam>
/// <param name="source">Die erste Liste.</param>
/// <param name="other">Die zweite Liste.</param>
/// <param name="equal">Eine Funktion zum überprüfen auf Gleichheit.</param>
/// <param name="ignoreOrder"><c>True</c>, wenn die Reihenfolge der Elemente ignoriert werden soll; andernfalls <c>false</c>.</param>
/// <returns><c>true</c>, wenn <paramref name="source"/> und <paramref name="other"/> in den Elementen übereinstimmen; andernfalls <c>false</c>.</returns>
public static bool AreItemsEqual<T>(this IEnumerable<T> source, IEnumerable<T> other, Func<T, T, bool> equal, bool ignoreOrder)
{
    if (source == null) throw new ArgumentNullException("source");
    if (other == null) throw new ArgumentNullException("other");
    if (equal == null) throw new ArgumentNullException("equal");

    using (var enu1 = source.GetEnumerator())
    {
        using (var enu2 = other.GetEnumerator())
        {
            bool b1 = true, b2 = true;
            if (ignoreOrder)
            {
                foreach (var dist in source.Distinct())
                    if (source.Count(x => equal(x, dist)) != other.Count(x => equal(x, dist)))
                        return false;

                while ((b1 = enu1.MoveNext()) & (b2 = enu2.MoveNext())) { }
            }
            else
                while ((b1 = enu1.MoveNext()) & (b2 = enu2.MoveNext()))
                {
                    if (!equal(enu1.Current, enu2.Current))
                        return false;
                }

            if (b1 != b2)
                return false;//one at end, the other not
            else
                return true;
        }
    }
}

3 Kommentare

  1. Wenn du folgendes machst:
    [code]
    string[] a6 = { „a“, „a“, „b“, „b“ };
    string[] a7 = { „a“, „a“, „a“, „b“ };
    Console.WriteLine(a6.AreItemsEqual(a7, (x, y) => x == y, true));
    [/code]
    … wird [b]True[/b] ausgegeben.
    Das sollte meiner Ansicht nach [b]False[/b] ergeben.

  2. Wenn du bei [b]ignoreOrder == true[/b] mit [b]Contains[/b] das Vorhandensein eines Wertes überprüfst, ist die Anzahl der gefundenen gleichen Werte irrelevant.
    Ich denke aber, die Anzahl der gleichen Werte muss übereinstimmen.

    Wenn du bei [b]ignoreOrder == true[/b] die Listen [b]source[/b] und [b]other[/b] sortieren würdest und dann den Vergleich wie bei [b]ignoreOrder == false[/b] machen würdest, müsste es funktionieren.
    Ich bin mir aber nicht sicher, ob und wie man das bei [b]IEnumerable[/b] machen kann.

  3. @Pirmin
    Du hast recht, so eine Anordnung von Arrayelementen kam in meinem Verwendungszweck nicht vor, darum habe ich es nicht darauf getestet.
    Deine Idee mit dem Sortieren der Liste würde zwar funktionieren, aber dafür bräuchte ich noch eine Funktion die die generischen Elemente vergleicht. Das wollte ich vermeiden.

    Also habe ich die einzigartigen Elemente aus [b]source[/b] heraus gesucht und die Anzahl dieser Elemente in [b]source[/b] und [b]other[/b] cmit einander verglichen. Sollten alle gleich sein, gehe ich nochmal beide Enumeratoren durch um die Anzahl zu überprüfen. Das geht sollte etwas schneller gehen, als zweimal Count aufzurufen.

    Ich habe das Snippet und die Testanwendung entsprechend angepasst.
    [b]Danke nochmal für diesen Hinweis![/b]