Überprüfen der Gleichheit zweier Scheiben


274

Wie kann ich überprüfen, ob zwei Scheiben gleich sind?


111
Die Frage handelt wirklich von einer einfachen Aufgabe, aber IMO ist es eine echte Frage mit einer sehr spezifischen Antwort. Wie es von Personen, an die ich mich nicht erinnern kann, jemals in den mit Go getaggten Fragen aktiv gewesen zu sein, als "keine echte Frage" hätte geschlossen werden können, ist mir ein Rätsel. Insbesondere: Die Frage ist nicht mehrdeutig, vollständig, auf ein einzelnes (wenn auch einfaches) Problem beschränkt, nicht rhetorisch und kann in ihrer aktuellen Form präzise und genau beantwortet werden. Der ==Operator ist in Go nur für einige Typen definiert, daher ist diese Frage auch legitim.
zzzz

4
Dennoch ist es keines der Dinge, die im nahen Grund erwähnt werden ("kann in seiner gegenwärtigen Form nicht vernünftigerweise beantwortet werden").
Rich Churcher

9
Hahaha, ich kann nicht glauben, dass dies wegen "keine echte Frage" geschlossen wurde. 1) Es ist nicht schwer zu sagen, was gefragt wird. 2) Die Frage ist nicht mehrdeutig / unvollständig / umfassend / unvernünftig. Das ist ein ziemlicher Missbrauch!
weberc2

5
Es scheint derzeit viel zu einfach zu sein, die Schaltfläche "Downvote" ("Ich denke, diese Frage zeigt keinen Aufwand und wird nicht gut gestellt") mit der Schaltfläche "Schließen" ("Ich denke, sie kann aus folgendem Grund nicht beantwortet werden) zu verwechseln. . "). Könnte daran liegen, dass enge Stimmen frei sind.
Kos

3
slice can only be compared to nilIch habe mich zufällig in Go entwickelt und bin darauf gestoßen. Ich habe mich gefragt, ob es einen idiomatischen Golang-Weg gibt, um die Slice-Gleichheit zu überprüfen. Wenn der Gleichheitsoperator nicht durch die Sprache definiert ist, finde ich es vernünftig, nach dem effizientesten Weg zu fragen um es zu erreichen. Die Frage musste nicht geschlossen werden
Abbordon

Antworten:


157

Sie müssen jedes der Elemente im Slice durchlaufen und testen. Gleichheit für Slices ist nicht definiert. Es gibt jedoch eine bytes.EqualFunktion, wenn Sie Werte vom Typ vergleichen []byte.

func testEq(a, b []Type) bool {

    // If one is nil, the other must also be nil.
    if (a == nil) != (b == nil) { 
        return false; 
    }

    if len(a) != len(b) {
        return false
    }

    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }

    return true
}

15
Vorschlag : for i, v := range a { if v != b[i] { return false } }.
zzzz

19
@zzzz Vorsicht, dies schlägt bei verschiedenen Längen fehl.
FiloSottile

2
Dies funktioniert nicht, wenn der Elementtyp == nicht unterstützt. Auch IIUC, Go hat nichts wie Generika. Dies bedeutet, dass Sie diese Funktion für jeden Elementtyp, den Sie unterstützen möchten, kopieren und einfügen müssen. Dies ist offensichtlich etwas, das mit der Sprache geliefert werden sollte. In der Tat (wenn auch mit der Magie des Reflektierens), und Victor liefert die Antwort. Die Tatsache, dass dies über dieser Antwort gewählt und höher gewählt wird, ist einfach verrückt ...
Allyourcode

5
Go as a language empfiehlt in der Regel, keine Reflexion zu verwenden, es sei denn, dies ist unbedingt erforderlich. Ja, es müsste für jeden Typ durchgeführt werden, aber es ist im Allgemeinen sowieso nicht etwas, was Sie oft tun. Reflect.DeepEqual kann auch etwas tun, was Sie nicht erwarten, z. B. sagen, dass zwei verschiedene Zeiger gleich sind, weil die Werte, auf die sie zeigen, gleich sind.
Stephen Weinberg

2
@FiloSottile Length wird vorher überprüft, die Schleife wird nur erreicht, wenn sich die Längen unterscheiden.
icza

258

Sie sollten Reflect.DeepEqual () verwenden.

DeepEqual ist eine rekursive Entspannung des Operators == von Go.

DeepEqual gibt an, ob x und y "zutiefst gleich" sind, wie folgt definiert. Zwei Werte identischen Typs sind zutiefst gleich, wenn einer der folgenden Fälle zutrifft. Werte unterschiedlicher Typen sind niemals zutiefst gleich.

Array-Werte sind tief gleich, wenn ihre entsprechenden Elemente tief gleich sind.

Strukturwerte sind zutiefst gleich, wenn die entsprechenden Felder, sowohl exportiert als auch nicht exportiert, sehr gleich sind.

Funktionswerte sind zutiefst gleich, wenn beide Null sind; sonst sind sie nicht zutiefst gleich.

Schnittstellenwerte sind zutiefst gleich, wenn sie zutiefst gleiche konkrete Werte enthalten.

Kartenwerte sind zutiefst gleich, wenn sie dasselbe Kartenobjekt sind oder wenn sie dieselbe Länge haben und ihre entsprechenden Schlüssel (mit Go-Gleichheit abgeglichen) sehr gleichen Werten zugeordnet sind.

Zeigerwerte sind zutiefst gleich, wenn sie mit dem Operator == von Go gleich sind oder wenn sie auf tief gleiche Werte verweisen.

Slice-Werte sind zutiefst gleich, wenn alle der folgenden Bedingungen erfüllt sind: Sie sind beide null oder beide nicht null, sie haben dieselbe Länge und entweder zeigen sie auf denselben Anfangseintrag desselben zugrunde liegenden Arrays (dh & x [0) ] == & y [0]) oder ihre entsprechenden Elemente (bis zur Länge) sind zutiefst gleich. Beachten Sie, dass ein nicht-Null-Leer-Slice und ein Null-Slice (z. B. [] Byte {} und [] Byte (Null)) nicht tief gleich sind.

Andere Werte - Zahlen, Bools, Strings und Kanäle - sind zutiefst gleich, wenn sie mit dem Operator == von Go gleich sind.


13
Eine sehr nützliche Antwort. Unabhängig von der allgemeinen Leistung des Reflect-Pakets ist es sehr schön, eine vorgefertigte Deep Equality-Funktion für Testfälle zu haben, bei denen Einfachheit und Korrektheit von größter Bedeutung sind.
WeakPointer

15
Ich habe gerade einen Benchmark durchgeführt und reflektiert. DeepEqual ist 150-mal langsamer als eine Schleife. Nur zu Ihrer Information, wenn jemand diese Methode in der Produktion anwenden möchte.
Nikdeapen

2
Es werden keine zufällig geordneten Slices mit denselben Elementen
verglichen

5
@Hemant_Negi zwei Slices sind nicht gleich, wenn sie eine andere Reihenfolge haben. Wenn Sie die Gleichheit zweier Slices vergleichen möchten, während Sie die Reihenfolge ignorieren, sortieren Sie sie und überprüfen oder verschieben Sie die Elemente von einem Slice in eine Karte. Überprüfen Sie dann, ob sich jedes Element auf dem anderen Slice in der Karte befindet. (
Stellen

3
Rob Pike (2011) über die Reflexion in Go und schrieb im offiziellen Go-Blog: "Es ist ein leistungsstarkes Tool, das mit Vorsicht verwendet und vermieden werden sollte, sofern dies nicht unbedingt erforderlich ist" blog.golang.org/laws-of-reflection . Ich würde die Reflexion im Produktionscode nicht nur zum Vergleichen von Slices verwenden. Das ist eine einfach zu schreibende Funktion. Beachten Sie jedoch, dass die gewählte Antwort auf diese Frage auch einen potenziellen Fehler aufweist, je nachdem, welches Verhalten Sie von ihr erwarten: Es wird festgestellt, dass Slices, die initialisiert wurden, sich aber noch bei len 0 und cap 0 befinden, nicht mit Slices übereinstimmen, die zuvor waren deklariert, aber nicht initialisiert.
Jrefior

44

Dies ist nur ein Beispiel für die Verwendung von Reflect.DeepEqual () , das in der Antwort von @ VictorDeryagin angegeben ist.

package main

import (
    "fmt"
    "reflect"
)

func main() {
    a := []int {4,5,6}
    b := []int {4,5,6}
    c := []int {4,5,6,7}

    fmt.Println(reflect.DeepEqual(a, b))
    fmt.Println(reflect.DeepEqual(a, c))

}

Ergebnis:

true
false

Probieren Sie es auf dem Go Playground aus


23

Wenn Sie zwei haben []byte, vergleichen Sie sie mit bytes.Equal . Die Golang-Dokumentation sagt:

Equal gibt einen Booleschen Wert zurück, der angibt, ob a und b dieselbe Länge haben und dieselben Bytes enthalten. Ein Null-Argument entspricht einem leeren Slice.

Verwendungszweck:

package main

import (
    "fmt"
    "bytes"
)

func main() {
    a := []byte {1,2,3}
    b := []byte {1,2,3}
    c := []byte {1,2,2}

    fmt.Println(bytes.Equal(a, b))
    fmt.Println(bytes.Equal(a, c))
}

Dies wird gedruckt

true
false

warum ist das nicht top
lurf jurv

3

Und im Moment ist hier https://github.com/google/go-cmp welche

soll eine leistungsfähigere und sicherere Alternative zum reflect.DeepEqualVergleich sein, ob zwei Werte semantisch gleich sind.

package main

import (
    "fmt"

    "github.com/google/go-cmp/cmp"
)

func main() {
    a := []byte{1, 2, 3}
    b := []byte{1, 2, 3}

    fmt.Println(cmp.Equal(a, b)) // true
}

1

Wenn Sie daran interessiert sind, einen Test zu schreiben, dann github.com/stretchr/testify/assertist Ihr Freund.

Importieren Sie die Bibliothek ganz am Anfang der Datei:

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

Dann machen Sie im Test:


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

Der angeforderte Fehler lautet:

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

assert.EqualInterne Verwendung, reflect.DeepEqualdie dazu führen kann, dass Ihre Tests langsamer ausgeführt werden und schließlich Ihre Pipeline.
Deepak Sah

@DeepakSah Haben Sie Benchmarks für den Leistungsunterschied? Meiner Erfahrung nach ist der Leistungsengpass in den Tests nicht gleich
hoch
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.