428 Stimmen

Überprüfen der Gleichheit von zwei Slices

Wie kann ich überprüfen, ob zwei Slices gleich sind, wenn die Operatoren == und != keine Option sind?

package main

import "fmt"

func main() {
    s1 := []int{1, 2}
    s2 := []int{1, 2}
    fmt.Println(s1 == s2)
}

Dies kompiliert nicht mit:

Ungültige Operation: s1 == s2 (Slice kann nur mit nil verglichen werden)

14voto

blackgreen Punkte 23721

Sie können == oder != nicht mit Slices verwenden, aber wenn Sie sie mit den Elementen verwenden können, hat Go 1.18 eine neue Funktion zum einfachen Vergleichen von zwei Slices, slices.Equal:

Equal gibt an, ob zwei Slices gleich sind: die gleiche Länge und alle Elemente gleich. Wenn die Längen unterschiedlich sind, gibt Equal false zurück. Andernfalls werden die Elemente in aufsteigender Indexreihenfolge verglichen, und der Vergleich endet bei der ersten ungleichen Paarung. Gleitkommawerte NaN werden nicht als gleich betrachtet.

Der Importpfad des slices-Pakets lautet golang.org/x/exp/slices. Der Code im exp-Paket ist experimentell und noch nicht stabil. Er wird schließlich in die Standardbibliothek in Go 1.19 verschoben.

Nichtsdestotrotz können Sie es bereits ab Go 1.18 verwenden (playground)

    sliceA := []int{1, 2}
    sliceB := []int{1, 2}
    equal := slices.Equal(sliceA, sliceB)
    fmt.Println(equal) // true

    type data struct {
        num   float64
        label string
    }

    sliceC := []data{{10.99, "Spielzeug"}, {500.49, "Telefon"}}
    sliceD := []data{{10.99, "Spielzeug"}, {200.0, "Telefon"}}
    equal = slices.Equal(sliceC, sliceD)
    fmt.Println(equal) // true

Wenn die Elemente des Slices keine Verwendung von == und != erlauben, können Sie slices.EqualFunc verwenden und eine geeignete Vergleichsfunktion für den Elementtyp definieren.

7voto

Falls du daran interessiert bist, einen Test zu schreiben, dann ist github.com/stretchr/testify/assert dein Freund.

Importiere die Bibliothek ganz am Anfang der Datei:

import (
    "github.com/stretchr/testify/assert"
)

Dann machst du innerhalb des Tests folgendes:

func TestEquality_SomeSlice (t * testing.T) {
    a := []int{1, 2}
    b := []int{2, 1}
    assert.Equal(t, a, b)
}

Der angezeigte Fehler wird sein:

                Diff:
                --- Expected
                +++ Actual
                @@ -1,4 +1,4 @@
                 ([]int) (len=2) {
                + (int) 1,
                  (int) 2,
                - (int) 2,
                  (int) 1,
Test:           TestEquality_SomeSlice

2voto

Wug Punkte 12718

Gedanke an einen ausgeklügelten Trick und dachte, ich würde ihn teilen.

Wenn Sie wissen wollen, ob zwei Slices identisch sind (das heißt, sie verweisen auf dieselbe Datenregion) anstatt nur gleich (der Wert an jedem Index einer Slice entspricht dem Wert im gleichen Index der anderen), können Sie sie effizient wie folgt vergleichen:

foo := []int{1,3,5,7,9,11,13,15,17,19}

// Diese beiden Slices sind genau identisch
subslice1 := foo[3:][:4]
subslice2 := foo[:7][3:]

slicesEqual := &subslice1[0]  == &subslice2[0]   && 
               len(subslice1) == len(subslice2)

Es gibt einige Einschränkungen bei dieser Art von Vergleich, insbesondere können leere Slices nicht auf diese Weise verglichen werden und die Kapazität der Slices wird nicht berücksichtigt. Daher ist diese "Identität" nur wirklich nützlich beim Lesen aus einer Slice oder beim Erstellen einer streng schmaleren Subslice, da jeder Versuch, die Slice zu vergrößern, von der Kapazität der Slices beeinflusst wird. Dennoch ist es sehr nützlich, "diese beiden riesigen Speicherblöcke sind tatsächlich derselbe Block, ja oder nein" effizient zu deklarieren.

1voto

pvlbzn Punkte 138

Um einen vollständigen Satz von Antworten zu haben: Hier ist eine Lösung mit Generik.

func IsEqual[A comparable](a, b []A) bool {
    // Kann nicht gleich sein, wenn die Länge unterschiedlich ist
    if len(a) != len(b) {
        return false
    }

    // Leere Arrays sind trivial gleich
    if len(a) == 0 {
        return true
    }

    // Zwei Zeiger, die bei jeder Iteration aufeinander zulaufen
    left := 0
    right := len(a) - 1

    for left <= right {
        if a[left] != b[left] || a[right] != b[right] {
            return false
        }

        left++
        right--
    }

    return true
}

Der Code verwendet die Strategie der "zwei Zeiger", was zu einer Laufzeitkomplexität von n / 2 führt, was immer noch O(n) ist, jedoch halb so viele Schritte wie bei einer linearen Überprüfung eins nach dem anderen.

Update: behobenen Bug bei der Gleichheitsprüfung gemäß @doublethink13

0voto

mapcuk Punkte 800

Es gibt die Funktion assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) zum Überprüfen von Slices.

Danke an Aaron für den Kommentar. Es ist nicht offensichtlich, daher betone ich, dass diese Assert-Funktion die Bibliothek "github.com/stretchr/testify/assert" benötigt.

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