Vérification de l'égalité de deux tranches

274

Comment puis-je vérifier si deux tranches sont égales?

wei2912
la source
111
La question concerne vraiment une tâche simple, mais l'OMI est une vraie question, avec une réponse très précise. Comment cela aurait pu être considéré comme "pas une vraie question" par, autant que je sache, des gens dont je ne me souviens pas avoir été actif dans les questions marquées Go, cela me dépasse. Plus précisément: la question est non ambiguë, complète, étroite à un problème unique (bien que simple), non rhétorique et peut être répondue avec précision et exactitude dans sa forme actuelle. L' ==opérateur n'est défini dans Go que pour certains types, de plus, cette question est également légitime.
zzzz
4
Pourtant, ce n'est aucune des choses mentionnées dans la raison proche ("ne peut raisonnablement pas être répondu dans sa forme actuelle").
Rich Churcher
9
Hahaha, je ne peux pas croire que cela a été fermé pour "pas une vraie question". 1) Il n'est pas difficile de dire ce qui est demandé. 2) La question n'est pas ambiguë / incomplète / large / déraisonnable. C'est tout à fait un abus!
weberc2
5
Il semble qu'il soit actuellement trop facile de confondre le bouton Downvote ("Je pense que cette question ne montre pas d'effort et n'est pas bien posée") avec le bouton Fermer ("Je pense qu'il ne peut pas être répondu pour la raison suivante .. . "). Peut-être parce que les votes serrés sont gratuits.
Kos
3
slice can only be compared to nilJe suis arrivé à développer dans Go et je me suis heurté à , et je me demandais s'il y avait un moyen golang idiomatique pour vérifier l'égalité des tranches ... si l'opérateur d'égalité n'est pas défini par le langage, alors je trouve raisonnable de demander le moyen le plus efficace pour l'accomplir. La question n'a pas dû être fermée
abgordon

Réponses:

157

Vous devez parcourir chacun des éléments de la tranche et tester. L'égalité pour les tranches n'est pas définie. Cependant, il existe une bytes.Equalfonction si vous comparez des valeurs de type []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
}
Stephen Weinberg
la source
15
Suggestion: for i, v := range a { if v != b[i] { return false } }.
zzzz
19
@zzzz Attention, cela échouera sur différentes longueurs.
FiloSottile
2
Cela ne fonctionne pas si le type d'élément ne prend pas en charge ==. De plus, IIUC, Go n'a rien de générique. Cela signifie que vous devez copier et coller cette fonction pour chaque type d'élément que vous souhaitez prendre en charge. C'est évidemment quelque chose qui devrait accompagner la langue. En fait, c'est le cas (quoique avec la magie du reflet), et Victor fournit la réponse. Le fait que cela soit choisi au-dessus de cette réponse, et plus voté est tout simplement
exaspérant
5
Aller comme une langue a tendance à recommander de ne pas utiliser la réflexion à moins que cela ne soit absolument nécessaire. Oui, cela devrait être fait pour chaque type, mais ce n'est généralement pas quelque chose que vous faites souvent de toute façon. De plus, reflect.DeepEqual peut faire quelque chose que vous ne vous attendez pas, comme dire que deux pointeurs différents sont égaux parce que les valeurs qu'ils pointent sont égales.
Stephen Weinberg
2
@FiloSottile Length est vérifié au préalable, la boucle n'est atteinte que si les longueurs diffèrent.
icza
259

Vous devez utiliser reflect.DeepEqual ()

DeepEqual est une relaxation récursive de l'opérateur == de Go.

DeepEqual indique si x et y sont «profondément égaux», définis comme suit. Deux valeurs de type identique sont profondément égales si l'un des cas suivants s'applique. Les valeurs de types distincts ne sont jamais profondément égales.

Les valeurs de tableau sont profondément égales lorsque leurs éléments correspondants sont profondément égaux.

Les valeurs de structure sont profondément égales si leurs champs correspondants, à la fois exportés et non exportés, sont profondément égaux.

Les valeurs de Func sont profondément égales si les deux sont nulles; sinon, ils ne sont pas profondément égaux.

Les valeurs d'interface sont profondément égales si elles contiennent des valeurs concrètes profondément égales.

Les valeurs de carte sont profondément égales si elles sont le même objet de carte ou si elles ont la même longueur et leurs clés correspondantes (appariées en utilisant l'égalité Go) correspondent à des valeurs profondément égales.

Les valeurs du pointeur sont profondément égales si elles sont égales à l'aide de l'opérateur Go == ou si elles pointent vers des valeurs profondément égales.

Les valeurs de tranche sont profondément égales lorsque toutes les conditions suivantes sont vraies: elles sont toutes les deux nulles ou non nulles, elles ont la même longueur, et soit elles pointent vers la même entrée initiale du même tableau sous-jacent (c'est-à-dire, & x [0 ] == & y [0]) ou leurs éléments correspondants (jusqu'à la longueur) sont profondément égaux. Notez qu'une tranche vide non nulle et une tranche nulle (par exemple, [] octet {} et [] octet (nul)) ne sont pas profondément égales.

D'autres valeurs - nombres, bools, chaînes et canaux - sont profondément égales si elles sont égales en utilisant l'opérateur == de Go.

Victor Deryagin
la source
13
Une réponse très utile. Indépendamment des performances générales du package, il est très agréable d'avoir une fonction d'égalité profonde préemballée à utiliser dans les cas de test où la simplicité et l'exactitude sont primordiales.
WeakPointer
15
Je viens de lancer un benchmark et de réfléchir. DeepEqual est 150 fois plus lent qu'une boucle. Juste pour info si quelqu'un veut utiliser cette méthode en production.
nikdeapen
2
Il ne compare pas les tranches classées au hasard avec les mêmes éléments :(
Hemant_Negi
5
@Hemant_Negi deux tranches ne sont pas égales si elles ont un ordre différent. Si vous souhaitez comparer l'égalité de deux tranches tout en ignorant l'ordre, triez-les puis vérifiez ou déplacez les éléments d'une tranche dans une carte, puis vérifiez que chaque élément de l'autre tranche se trouve dans la carte. (assurez-vous également qu'ils ont la même longueur)
robbert229
3
Rob Pike (en 2011) sur la réflexion dans Go, écrit dans le blog officiel Go: "C'est un outil puissant qui doit être utilisé avec précaution et évité sauf si strictement nécessaire" blog.golang.org/laws-of-reflection . Je n'utiliserais pas la réflexion dans le code de production juste pour comparer des tranches. C'est une fonction facile à écrire. Mais notez qu'il y a aussi une faille potentielle dans la réponse choisie à cette question, selon le comportement que vous en attendez: elle trouvera que les tranches qui ont été initialisées mais sont toujours à len 0 et le cap 0 ne correspondent pas aux tranches qui ont été déclaré mais non initialisé.
jrefior
44

C'est juste un exemple en utilisant reflect.DeepEqual () qui est donné dans la réponse de @ 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))

}

Résultat:

true
false

Essayez-le dans Go Playground

Akavall
la source
23

Si vous en avez deux []byte, comparez-les en utilisant bytes.Equal . La documentation de Golang dit:

Equal renvoie un booléen indiquant si a et b ont la même longueur et contiennent les mêmes octets. Un argument nil équivaut à une tranche vide.

Usage:

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

Cela imprimera

true
false
KeksArmee
la source
pourquoi est-ce pas top
lurf jurv
3

Et pour l'instant, voici https://github.com/google/go-cmp qui

est destiné à être une alternative plus puissante et plus sûre reflect.DeepEqualpour comparer si deux valeurs sont sémantiquement égales.

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
}
lk_vc
la source
1

Dans le cas où vous êtes intéressé à écrire un test, alors github.com/stretchr/testify/assertc'est votre ami.

Importez la bibliothèque au tout début du fichier:

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

Ensuite, à l'intérieur du test, vous effectuez:


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

L'erreur demandée sera:

                Diff:
                --- Expected
                +++ Actual
                @@ -1,4 +1,4 @@
                 ([]int) (len=2) {
                + (int) 1,
                  (int) 2,
                - (int) 2,
                  (int) 1,
Test:           TestEquality_SomeSlice
Gabriel Furstenheim
la source
assert.Equalutilise en interne reflect.DeepEqualce qui pourrait ralentir vos tests et éventuellement votre pipeline.
Deepak Sah
@DeepakSah Avez-vous des repères pour la différence de performance? D'après mon expérience, le goulot d'étranglement des performances dans les tests n'est pas dans l'affirmation égale, et vous obtenez des messages de grande qualité qui ont une augmentation de la productivité
Gabriel Furstenheim