Sprawdzanie równości dwóch plasterków


274

Jak mogę sprawdzić, czy dwa plasterki są równe?


111
Pytanie naprawdę dotyczy prostego zadania, ale IMO to prawdziwe pytanie z bardzo konkretną odpowiedzią. Jak to mogło być zamknięte jako „nie prawdziwe pytanie” przez, o ile widzę, ludzi, których nie pamiętam, że kiedykolwiek byłem aktywny w pytaniach oznaczonych Go, jest poza mną. W szczególności: pytanie jest niejednoznaczne, kompletne, wąskie do jednego (choć prostego) problemu, nie retoryczne i można na nie odpowiedzieć precyzyjnie i dokładnie w jego obecnej formie. ==Operator definiuje Przejdź do tylko niektórych typów, tak zresztą, to pytanie jest również zasadny.
zzzz

4
Mimo to nie jest to żadna z rzeczy wymienionych w ścisłym związku („nie można racjonalnie odpowiedzieć w obecnej formie”).
Bogaty Churcher

9
Hahaha, nie mogę uwierzyć, że to zostało zamknięte z powodu „nie prawdziwego pytania”. 1) Nietrudno powiedzieć, o co pytano. 2) Pytanie nie jest dwuznaczne / niepełne / szerokie / nierozsądne. To całkiem nadużycie!
weberc2

5
Wygląda na to, że obecnie zbyt łatwo jest pomylić przycisk Downvote („Myślę, że to pytanie nie pokazuje wysiłku i nie jest dobrze zadane”) z przyciskiem Close („Myślę, że nie można na nie odpowiedzieć z następującego powodu ... . ”). Może dlatego, że głosowanie w trybie Close jest bezpłatne.
Kos,

3
Zdarzyło się, że rozwijałem w Go i slice can only be compared to nilnatknąłem się na niego , i zastanawiałem się, czy istnieje idiomatyczny sposób golanga, aby sprawdzić równość plasterków ... jeśli operator równości nie jest zdefiniowany przez język, uważam, że rozsądnie jest zapytać o najbardziej skuteczny sposób aby to osiągnąć. Pytanie nie musiało być zamknięte
abgordon,

Odpowiedzi:


157

Musisz zapętlić każdy element w plasterku i przetestować. Równość plasterków nie jest zdefiniowana. Istnieje jednak bytes.Equalfunkcja, jeśli porównujesz wartości typu []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
Sugestia: for i, v := range a { if v != b[i] { return false } }.
zzzz

19
@zzzz Ostrożnie, to zawiedzie na różnych długościach.
FiloSottile

2
To nie działa, jeśli typ elementu nie obsługuje ==. Ponadto IIUC, Go nie ma czegoś takiego jak leki generyczne. Oznacza to, że musisz skopiować i wkleić tę funkcję dla każdego typu elementu, który chcesz obsługiwać. Jest to oczywiście coś, co powinno być dostarczane z tym językiem. W rzeczywistości tak jest (choć z magią refleksji), a Victor udziela odpowiedzi. Fakt, że wybrano tę odpowiedź ponad tę odpowiedź i jest bardziej głosowany, jest po prostu szalony ...
allyourcode

5
Idź, jako że język raczej nie zaleca używania refleksji, chyba że jest to absolutnie konieczne. Tak, należy to zrobić dla każdego typu, ale i tak zazwyczaj nie jest to często robione. Ponadto, reflect.DeepEqual może zrobić coś, czego się nie spodziewasz, na przykład powiedzieć, że dwa różne wskaźniki są równe, ponieważ wartości, które wskazują, są równe.
Stephen Weinberg,

2
@FiloSottile Długość jest wcześniej sprawdzana, pętla jest osiągana tylko wtedy, gdy długości różnią się.
icza

259

Powinieneś użyć reflect.DeepEqual ()

DeepEqual to rekurencyjna relaksacja operatora Go = =.

DeepEqual informuje, czy xiy są „głęboko równe”, zdefiniowane w następujący sposób. Dwie wartości tego samego typu są głęboko równe, jeśli ma zastosowanie jeden z następujących przypadków. Wartości różnych typów nigdy nie są głęboko równe.

Wartości tablic są głęboko równe, gdy odpowiadające im elementy są głęboko równe.

Wartości struktur są głęboko równe, jeśli odpowiadające im pola, zarówno eksportowane, jak i nie eksportowane, są głęboko równe.

Wartości Func są głęboko równe, jeśli oba są równe zero; w przeciwnym razie nie są głęboko równi.

Wartości interfejsów są głęboko równe, jeśli zawierają głęboko równe konkretne wartości.

Wartości map są głęboko równe, jeśli są tym samym obiektem mapy lub mają taką samą długość, a odpowiadające im klucze (dopasowane przy użyciu Go równości) mapują na głęboko równe wartości.

Wartości wskaźnika są głęboko równe, jeśli są równe za pomocą operatora Go == lub jeśli wskazują na głęboko równe wartości.

Wartości wycinków są głęboko równe, gdy spełnione są wszystkie poniższe warunki: oba są zerowe lub oba nie-zerowe, mają tę samą długość i albo wskazują na ten sam początkowy wpis tej samej podstawowej tablicy (to jest, & x [0 ] == i y [0]) lub odpowiadające im elementy (do długości) są głęboko równe. Zauważ, że pusty pusty plasterek i zerowy plasterek (na przykład [] bajt {} i [] bajt (zero)) nie są głęboko równe.

Inne wartości - liczby, boole, ciągi i kanały - są głęboko równe, jeśli są równe za pomocą operatora Go = =.


13
Bardzo przydatna odpowiedź. Niezależnie od ogólnej wydajności pakietu odzwierciedlającego, bardzo miło jest mieć paczkowaną funkcję głębokiej równości do użycia w przypadkach testowych, w których najważniejsza jest prostota i poprawność.
WeakPointer

15
Właśnie uruchomiłem test porównawczy i refleksyjny. Głębokość jest 150 razy wolniejsza niż pętla. Tylko FYI, jeśli ktoś chce użyć tej metody w produkcji.
nikdeapen,

2
Nie porównuje losowo uporządkowanych plasterków z tymi samymi przedmiotami :(
Hemant_Negi

5
@Hemant_Negi dwa plasterki nie są równe, jeśli mają inną kolejność. Jeśli chcesz porównać równość dwóch wycinków, ignorując kolejność, posortuj je, a następnie zaznacz lub przenieś elementy z jednego wycinka na mapę, a następnie sprawdź, czy każdy element na drugim wycinku znajduje się na mapie. (dodatkowo upewnij się, że mają taką samą długość)
robbert229

3
Rob Pike (w 2011 r.) O refleksji w Go, pisząc na oficjalnym blogu Go: „To potężne narzędzie, którego należy używać ostrożnie i unikać, chyba że jest to absolutnie konieczne” blog.golang.org/laws-of-reflection . Nie używałbym refleksji w kodzie produkcyjnym tylko do porównywania plasterków. To łatwa funkcja do napisania. Należy jednak pamiętać, że w wybranej odpowiedzi na to pytanie istnieje także potencjalna wada, w zależności od oczekiwanego zachowania: okaże się, że wycinki, które zostały zainicjowane, ale wciąż mają wartość 0, a wielkość 0 nie pasują do wycinków, które zostały zadeklarowane, ale nie zainicjowane.
jrefior

44

To tylko przykład użycia reflect.DeepEqual () podanego w odpowiedzi @ VictorDeryagin.

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))

}

Wynik:

true
false

Wypróbuj Go Playground


23

Jeśli masz dwa []byte, porównaj je za pomocą bytes.Equal . Dokumentacja Golanga mówi:

Równe zwraca wartość logiczną raportującą, czy aib mają tę samą długość i zawierają te same bajty. Argument zerowy jest równoważny pustemu wycinkowi.

Stosowanie:

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))
}

To zostanie wydrukowane

true
false

dlaczego to nie jest najlepsze
lurf jurv

3

A na razie tutaj jest https://github.com/google/go-cmp które

ma być silniejszą i bezpieczniejszą alternatywą do reflect.DeepEqualporównywania, czy dwie wartości są semantycznie równe.

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

Jeśli jesteś zainteresowany pisaniem testu, to github.com/stretchr/testify/assertjest twój przyjaciel.

Zaimportuj bibliotekę na samym początku pliku:

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

Następnie w ramach testu wykonujesz:


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

Zgłoszony błąd to:

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

assert.Equalzastosowania wewnętrzne, reflect.DeepEqualktóre mogą sprawić, że testy będą działały wolniej, a ostatecznie potok.
Deepak Sah

@DeepakSah Czy masz wzorce odniesienia dla różnicy wydajności? Z mojego doświadczenia wynika, że ​​wąskie gardło wydajności w testach nie jest równe, a Ty otrzymujesz wiadomości o doskonałej jakości, które zwiększają produktywność
Gabriel Furstenheim,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.