Frage

Ich möchte den Inhalt einiger Sammlungen in meiner Equals-Methode vergleichen.Ich habe ein Wörterbuch und eine IList.Gibt es dafür eine integrierte Methode?

Bearbeitet:Ich möchte zwei Wörterbücher und zwei ILists vergleichen, daher ist meiner Meinung nach klar, was Gleichheit bedeutet: Wenn die beiden Wörterbücher dieselben Schlüssel enthalten, die denselben Werten zugeordnet sind, sind sie gleich.

War es hilfreich?

Lösung

Enumerable.SequenceEqual

Bestimmt, ob zwei Sequenzen gleich sind, indem ihre Elemente mithilfe eines angegebenen IEqualityComparer(T) verglichen werden.

Sie können die Liste und das Wörterbuch nicht direkt vergleichen, aber Sie können die Werteliste aus dem Wörterbuch mit der Liste vergleichen

Andere Tipps

Wie andere vorgeschlagen und angemerkt haben, SequenceEqual ist auftragsabhängig.Um dieses Problem zu lösen, können Sie das Wörterbuch nach Schlüssel sortieren (der eindeutig ist und die Sortierung daher immer stabil ist) und es dann verwenden SequenceEqual.Der folgende Ausdruck prüft, ob zwei Wörterbücher unabhängig von ihrer internen Reihenfolge gleich sind:

dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

BEARBEITEN: Wie Jeppe Stig Nielsen betonte, haben einige Objekte eine IComparer<T> das ist mit ihrem unvereinbar IEqualityComparer<T>, was zu falschen Ergebnissen führt.Wenn Sie Schlüssel mit einem solchen Objekt verwenden, müssen Sie einen korrekten Wert angeben IComparer<T> für diese Schlüssel.Bei Zeichenfolgenschlüsseln (bei denen dieses Problem auftritt) müssen Sie beispielsweise Folgendes tun, um korrekte Ergebnisse zu erhalten:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))

Zusätzlich zu den genannten Sequenzgleich, welche

ist wahr, wenn zwei Listen gleich lang sind und ihre entsprechenden Elemente entsprechend einem Vergleich gleich vergleichen

(Dies kann der Standardvergleicher sein, d. h.eine Überschreibung Equals())

Es ist erwähnenswert, dass dies in .Net4 der Fall ist SetEquals An ISet Objekte welche

ignoriert die Reihenfolge der Elemente und alle doppelten Elemente.

Wenn Sie also eine Liste von Objekten haben möchten, diese aber nicht in einer bestimmten Reihenfolge vorliegen müssen, sollten Sie dies in Betracht ziehen ISet (wie ein HashSet) könnte die richtige Wahl sein.

Werfen Sie einen Blick auf die Enumerable.SequenceEqual Methode

var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);

.NET verfügt nicht über leistungsstarke Tools zum Vergleichen von Sammlungen.Ich habe eine einfache Lösung entwickelt, die Sie unter dem folgenden Link finden:

http://robertbouillon.com/2010/04/29/comparing-collections-in-net/

Dadurch wird unabhängig von der Reihenfolge ein Gleichheitsvergleich durchgeführt:

var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;

Dadurch wird überprüft, ob Elemente hinzugefügt/entfernt wurden:

var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added;   //Sally
var inbothlists = diff.Equal;   //Bob

Dadurch wird angezeigt, welche Elemente im Wörterbuch geändert wurden:

var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
  Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa

Ich wusste nichts über die Enumerable.SequenceEqual-Methode (man lernt jeden Tag etwas ...), aber ich wollte die Verwendung einer Erweiterungsmethode vorschlagen;etwas wie das:

    public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
    {
        if (InternalList.Count != ExternalList.Count)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < InternalList.Count; i++)
            {
                if (InternalList[i] != ExternalList[i])
                    return false;
            }
        }

        return true;

    }

Interessanterweise sieht es so aus, als hätte Microsoft die von mir beschriebene Funktion für Sie erstellt, nachdem Sie sich zwei Sekunden Zeit genommen haben, um über SequenceEqual zu lesen.

Dies beantwortet Ihre Fragen nicht direkt, wird aber sowohl von den MS-TestTools als auch von NUnit bereitgestellt

 CollectionAssert.AreEquivalent

Das macht so ziemlich das, was Sie wollen.

Zum Vergleichen von Sammlungen können Sie auch LINQ verwenden. Enumerable.Intersect gibt alle Paare zurück, die gleich sind.Sie können zwei Wörterbücher wie folgt vergleichen:

(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count

Der erste Vergleich ist notwendig, weil dict2 kann alle Schlüssel von enthalten dict1 und mehr.

Sie können sich auch Variationen ausdenken, indem Sie verwenden Enumerable.Except Und Enumerable.Union die zu ähnlichen Ergebnissen führen.Kann aber verwendet werden, um die genauen Unterschiede zwischen Sätzen zu bestimmen.

Wie wäre es mit diesem Beispiel:

 static void Main()
{
    // Create a dictionary and add several elements to it.
    var dict = new Dictionary<string, int>();
    dict.Add("cat", 2);
    dict.Add("dog", 3);
    dict.Add("x", 4);

    // Create another dictionary.
    var dict2 = new Dictionary<string, int>();
    dict2.Add("cat", 2);
    dict2.Add("dog", 3);
    dict2.Add("x", 4);

    // Test for equality.
    bool equal = false;
    if (dict.Count == dict2.Count) // Require equal count.
    {
        equal = true;
        foreach (var pair in dict)
        {
            int value;
            if (dict2.TryGetValue(pair.Key, out value))
            {
                // Require value be equal.
                if (value != pair.Value)
                {
                    equal = false;
                    break;
                }
            }
            else
            {
                // Require key be present.
                equal = false;
                break;
            }
        }
    }
    Console.WriteLine(equal);
}

Anstand : https://www.dotnetperls.com/dictionary-equals

Für geordnete Sammlungen (Liste, Array) verwenden SequenceEqual

für HashSet-Nutzung SetEquals

Für das Wörterbuch können Sie Folgendes tun:

namespace System.Collections.Generic {
  public static class ExtensionMethods {
    public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
      if (object.ReferenceEquals(d1, d2)) return true; 
      if (d2 is null || d1.Count != d2.Count) return false;
      foreach (var (d1key, d1value) in d1) {
        if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
        if (!d1value.Equals(d2value)) return false;
      }
      return true;
    }
  }
}

(Eine optimiertere Lösung verwendet die Sortierung, aber das erfordert IComparable<TValue>)

NEIN.Der Sammlungsrahmen kennt kein Gleichheitskonzept.Wenn man darüber nachdenkt, gibt es keine Möglichkeit, Sammlungen zu vergleichen, die nicht subjektiv sind.Wenn Sie beispielsweise Ihre IList mit Ihrem Wörterbuch vergleichen, wären sie gleich, wenn alle Schlüssel in der IList wären, alle Werte in der IList wären oder wenn beide in der IList wären?Es gibt keine offensichtliche Möglichkeit, diese beiden Sammlungen zu vergleichen, ohne zu wissen, wofür sie verwendet werden sollen. Daher macht eine allgemeine Gleichheitsmethode keinen Sinn.

Nein, da das Framework nicht weiß, wie es den Inhalt Ihrer Listen vergleicht.

Guck dir das an:

http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx

public bool CompareStringLists(List<string> list1, List<string> list2)
{
    if (list1.Count != list2.Count) return false;

    foreach(string item in list1)
    {
        if (!list2.Contains(item)) return false;
    }

    return true;
}

Das gab es nicht, gibt es nicht und könnte es auch nicht geben, zumindest würde ich das glauben.Der Grund dafür ist, dass die Sammlungsgleichheit wahrscheinlich ein benutzerdefiniertes Verhalten ist.

Elemente in Sammlungen sollten nicht in einer bestimmten Reihenfolge vorliegen, obwohl sie von Natur aus eine Reihenfolge haben. Darauf sollten sich die Vergleichsalgorithmen nicht verlassen.Angenommen, Sie haben zwei Sammlungen von:

{1, 2, 3, 4}
{4, 3, 2, 1}

Sind sie gleich oder nicht?Sie müssen es wissen, aber ich weiß nicht, was Ihr Standpunkt ist.

Sammlungen sind standardmäßig konzeptionell ungeordnet, bis die Algorithmen die Sortierregeln bereitstellen.Dasselbe, worauf Sie SQL Server aufmerksam machen wird, ist, dass Sie bei der Paginierung Sortierregeln angeben müssen:

https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

Noch zwei weitere Sammlungen:

{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}

Sind sie wiederum gleich oder nicht?Du sagst es mir ..

Die Elementwiederholbarkeit einer Sammlung spielt in verschiedenen Szenarien eine Rolle, und einige Sammlungen mögen dies Dictionary<TKey, TValue> Erlauben Sie nicht einmal wiederholte Elemente.

Ich glaube, dass diese Art der Gleichheit anwendungsdefiniert ist und das Framework daher nicht alle möglichen Implementierungen bereitstellt.

Nun, im Allgemeinen Enumerable.SequenceEqual ist gut genug, gibt aber im folgenden Fall false zurück:

var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false

Ich habe einige Antworten auf Fragen wie diese gelesen (Sie können Google für sie) und was ich im Allgemeinen verwenden würde:

public static class CollectionExtensions {
    public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
        if(object.ReferenceEquals(first, second)) {
            return true;
        }

        if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
            return Enumerable.SequenceEqual(first, second);
        }

        if(first is ICollection<T> && second is ICollection<T>) {
            if(first.Count()!=second.Count()) {
                return false;
            }
        }

        first=first.OrderBy(x => x.GetHashCode());
        second=second.OrderBy(x => x.GetHashCode());
        return CollectionExtensions.Represents(first, second);
    }
}

Das bedeutet, dass eine Sammlung die andere in ihren Elementen repräsentiert, auch wiederholt, ohne die ursprüngliche Reihenfolge zu berücksichtigen.Einige Anmerkungen zur Implementierung:

  • GetHashCode() dient nur der Ordnung, nicht der Gleichheit;Ich denke, dass es in diesem Fall ausreicht

  • Count() zählt die Sammlung nicht wirklich auf und fällt direkt in die Eigenschaftsimplementierung von ICollection<T>.Count

  • Wenn die Referenzen gleich sind, ist es nur Boris

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top