26 Stimmen

Vergleichen Sie zwei .NET-Array-Objekte

Ich versuche, zwei .NET-Arrays zu vergleichen. Hier ist eine offensichtliche Implementierung für den Vergleich von Byte-Arrays:

bool AreEqual(byte[] a, byte[] b){
    if(a.Length != b.Length)
        return false;
    for(int i = 0; i < a.Length; i++)
        if(a[i] != b[i])
            return false;

    return true;
}

Eine raffiniertere Herangehensweise kann hier (über Google) gefunden werden.

  1. Was ist der einfachste Weg (mit weniger Code, aber lesbar), um zwei .NET-Arrays zu vergleichen?
  2. Was ist der effizienteste Weg, um zwei .NET-Arrays zu vergleichen?

2 Stimmen

Sie könnten auch ein frühes Beenden hinzufügen, wenn sie referenzgleich sind.

50voto

Christian C. Salvadó Punkte 763569

Sie könnten SequenceEqual verwenden:

string[] a = { "1", "2", "3" };
string[] b = { "1", "2", "3" };

bool sindGleich = a.SequenceEqual(b); // true

string[] c = { "1", "2", "5" };
sindGleich = a.SequenceEqual(c);      // false

3 Stimmen

Diese Seite enthält einige Leistungsdaten und behauptet, dass SequenceEqual etwa 10 Mal langsamer ist als eine benutzerdefinierte Implementierung mit einer Schleife. Ich frage mich warum.

2 Stimmen

Die Methode SequenceEqual ist standardmäßig nicht verfügbar, du musst System.Linq verwenden. Gut zu wissen, falls du verwirrt bist (wie ich es war).

18voto

Jon Skeet Punkte 1325502

Ich finde Kathys Ansatz gut. Ich würde persönlich den Vergleichenden ausdrücklich angeben lassen:

bool AreEqual(T[] a, T[] b)
{
    return AreEqual(a, b, EqualityComparer.Default);
}

bool AreEqual(T[] a, T[] b, IEqualityComparer comparer)
{
    // Handle identity comparison, including comparing nulls
    if (a == b)
    {
        return true;
    }

    if (a == null || b == null)
    {
        return false;
    }

    if(a.Length != b.Length)
    {
        return false;
    }

    for(int i = 0; i < a.Length; i++)
    {
        if(!comparer.Equals(a[i], b[i]))
        {
            return false;
        }
    }
    return true;
}

SequenceEqual wie von CMS erwähnt ist gut, aber aufgrund seiner Verallgemeinerung über IEnumerable glaube ich nicht, dass er das "early out" machen kann, wenn die Längen nicht übereinstimmen. (Es ist möglich, dass er beide Sequenzen überprüft, die IList implementieren, um direkt die Count zu prüfen.) Sie könnten noch etwas mehr verallgemeinern, um IList zu verwenden

bool AreEqual(IList a, IList b, IEqualityComparer comparer)
{
    if(a.Count != b.Count)
    {
        return false;
    }
    for(int i = 0; i < a.Count; i++)
    {
        if(!comparer.Equals(a[i], b[i]))
        {
            return false;
        }
    }
    return true;
}

Die direkte Array-Version wird wahrscheinlich am effizientesten sein - die Hinzufügung von Allgemeinheit und Abstraktion beeinträchtigt in der Regel die Leistung, obwohl es darauf ankommt, ob es für Ihre Anwendung signifikant ist.

4 Stimmen

Sollten die obigen Code-Snippets nicht if (!comparer.Equals(a[i], b[i]) return false enthalten? Habe ich gerade eine Anomalie in meinem Universum entdeckt :)

0 Stimmen

Benötigt auch eine schließende Klammer nach der zweiten 'if'-Anweisung.

0 Stimmen

@Jon Könntest du bitte erklären, was der Vorteil ist, den Vergleicher explizit anzugeben?

9voto

Nico Punkte 1514

Mit dem Aufkommen von .NET 4 können Sie die von .NET-Arrays bereitgestellte Methode Equals() verwenden, die vom Interface IStructuralEquatable explizit implementiert wird. Dann könnte der Code so aussehen (ich habe das Beispiel von CMS neu geschrieben):

string[] a = { "1", "2", "3" };
string[] b = { "1", "2", "3" };
bool result = ((IStructuralEquatable)a).Equals(b, StructuralComparisons.StructuralEqualityComparer);
// das Ergebnis ergibt true.

(IStructuralEquatable ist auch in Tupeln implementiert (ebenfalls neu in .NET 4)).

4 Stimmen

Oder verwenden Sie StructuralComparisons.StructuralEqualityComparer.Compare(a,b‌​)

1 Stimmen

Vielen Dank Chris! Ihre Lösung hat einen wichtigen Vorteil gegenüber meiner: sie ist null-sensibel.

0voto

Igor Zelaya Punkte 4107

Vielleicht so etwas?

static bool AreEqual(T[] a, T[] b) 
{
    bool areEqual = false ;
    T[] result = a.Intersect(b.AsEnumerable()).ToArray();
    areEqual = (result.Length == a.Length) && (result.Length == b.Length);
    return areEqual;
}

Ich bin mir allerdings nicht sicher, wie sich dies auf die Leistung auswirkt.

BEARBEITEN

Überarbeitete Version unter Berücksichtigung der Vorschläge von Jon:

static bool AreEqual(T[] a, T[] b) 
{
    return a.SequenceEqual(b);
}

0 Stimmen

Wenn Sie LINQ verwenden können und die Leistungseinbuße gegenüber der direkten Verwendung von Arrays nicht stört (und früh bei unterschiedlichen Längen abbricht), ist SequenceEqual der richtige Weg nach vorne.

1 Stimmen

Diese Lösung schlägt fehl, wenn Duplikate vorhanden sind: { 1, 1, 1} = { 1, 1, 1} gibt false zurück. Sie berücksichtigt auch nicht die Reihenfolge: { 1, 2} != {2, 1} gibt true zurück.

0 Stimmen

"{1, 2} != {2, 1} ergibt true" sollte bedeuten, dass die Reihenfolge berücksichtigt wird, oder?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X