Feedback

C# - Items zweier Listen vergleichen

Veröffentlicht von am 2/26/2014
(0 Bewertungen)
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.

Benötigte Namespaces
System
System.Collections.Generic
System.Linq

Hinweis
Die LINQ Methode SequenceEqual erziehlt ein ähnliches Ergebnis. Jedoch erlaubt die Methode keine Angabe, ob die Anordnung der Elemente beachtet werden soll.

Testanwendung
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();
/// <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 zum Snippet

Pirmin schrieb am 3/14/2014:
Wenn du folgendes machst:

string[] a6 = { "a", "a", "b", "b" };
string[] a7 = { "a", "a", "a", "b" };
Console.WriteLine(a6.AreItemsEqual(a7, (x, y) => x == y, true));

... wird True ausgegeben.
Das sollte meiner Ansicht nach False ergeben.
Pirmin schrieb am 3/14/2014:
Wenn du bei ignoreOrder == true mit Contains 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 ignoreOrder == true die Listen source und other sortieren würdest und dann den Vergleich wie bei ignoreOrder == false machen würdest, müsste es funktionieren.
Ich bin mir aber nicht sicher, ob und wie man das bei IEnumerable<T> machen kann.
Koopakiller schrieb am 3/15/2014:
@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 source heraus gesucht und die Anzahl dieser Elemente in source und other 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.
Danke nochmal für diesen Hinweis!
 

Logge dich ein, um hier zu kommentieren!