Comprobando la igualdad de dos rebanadas

274

¿Cómo puedo verificar si dos rebanadas son iguales?

wei2912
fuente
111
La pregunta realmente se trata de una tarea simple, pero IMO es una pregunta real, con una respuesta muy específica. Por lo que puedo ver, las personas que no recuerdo haber estado activas en las preguntas etiquetadas de Go podrían haber sido cerradas como "una pregunta no real". Específicamente: la pregunta no es ambigua, completa, estrecha a un solo problema (aunque simple), no retórica y puede responderse con precisión y precisión en su forma actual. El ==operador se define en Ir solo para algunos tipos, por lo tanto, esta pregunta también es legítima.
zzzz
44
Aún así, no es ninguna de las cosas mencionadas en la razón cercana ("no se puede responder razonablemente en su forma actual").
Rich Churcher
9
Jajaja, no puedo creer que esto se haya cerrado por "no es una pregunta real". 1) No es difícil saber qué se pregunta. 2) La pregunta no es ambigua / incompleta / amplia / irrazonable. ¡Esto es un abuso!
weberc2
55
Parece que actualmente es demasiado fácil confundir el botón Downvote ("Creo que esta pregunta no muestra esfuerzo y no está bien formulada") con el botón Cerrar ("Creo que no se puede responder por la siguiente razón ... "). Puede ser porque los votos cerrados son gratuitos.
Kos
3
Pasó a desarrollarse en Go y se topó con slice can only be compared to nil, y me preguntaba si hay una forma idiomática de golang para verificar la igualdad de corte ... si el operador de igualdad no está definido por el lenguaje, entonces me parece razonable preguntar la forma más eficiente para lograrlo La pregunta no necesitaba ser cerrada
abgordon

Respuestas:

157

Debe recorrer cada uno de los elementos en el segmento y probar. La igualdad para los cortes no está definida. Sin embargo, hay una bytes.Equalfunción si está comparando valores de tipo []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
fuente
15
Sugerencia: for i, v := range a { if v != b[i] { return false } }.
zzzz
19
@zzzz Cuidado, esto fallará en diferentes longitudes.
FiloSottile
2
Esto no funciona si el tipo de elemento no admite ==. Además, IIUC, Go no tiene nada como genéricos. Esto significa que debe copiar y pegar esta función para cada tipo de elemento que desee admitir. Obviamente, esto es algo que debería enviarse con el idioma. De hecho, lo hace (aunque con la magia de reflexionar), y Victor proporciona la respuesta. El hecho de que este se elige por encima de esa respuesta, y más altamente votó es simplemente enloquecedor ...
allyourcode
55
Ir como un idioma tiende a recomendar no usar la reflexión a menos que sea absolutamente necesario. Sí, tendría que hacerse para cada tipo, pero en general no es algo que haga a menudo de todos modos. Además, reflexiona. DeepEqual puede hacer algo que no esperas, como decir que dos punteros diferentes son iguales porque los valores que señalan son iguales.
Stephen Weinberg
2
@FiloSottile Length se verifica de antemano, el ciclo solo se alcanza si las longitudes difieren.
icza
259

Debe usar reflect.DeepEqual ()

DeepEqual es una relajación recursiva del operador Go's ==.

DeepEqual informa si xey son "profundamente iguales", definidos de la siguiente manera. Dos valores de tipo idéntico son profundamente iguales si se aplica uno de los siguientes casos. Los valores de distintos tipos nunca son profundamente iguales.

Los valores de matriz son profundamente iguales cuando sus elementos correspondientes son profundamente iguales.

Los valores de estructura son profundamente iguales si sus campos correspondientes, tanto exportados como no exportados, son profundamente iguales.

Los valores de func son profundamente iguales si ambos son nulos; de lo contrario no son profundamente iguales.

Los valores de la interfaz son profundamente iguales si tienen valores concretos profundamente iguales.

Los valores del mapa son profundamente iguales si son el mismo objeto de mapa o si tienen la misma longitud y sus teclas correspondientes (emparejadas usando la igualdad Go) se asignan a valores profundamente iguales.

Los valores del puntero son profundamente iguales si son iguales usando el operador Go == o si apuntan a valores profundamente iguales.

Los valores de corte son profundamente iguales cuando se cumple todo lo siguiente: ambos son nulos o ambos no nulos, tienen la misma longitud y apuntan a la misma entrada inicial de la misma matriz subyacente (es decir, & x [0 ] == & y [0]) o sus elementos correspondientes (hasta la longitud) son profundamente iguales. Tenga en cuenta que un segmento vacío no nulo y un segmento nulo (por ejemplo, [] byte {} y [] byte (nil)) no son profundamente iguales.

Otros valores - números, bools, cadenas y canales - son profundamente iguales si son iguales usando el operador Go's ==.

Victor Deryagin
fuente
13
Una respuesta muy útil. Independientemente del rendimiento general del paquete reflejado, es muy bueno tener una función de igualdad profunda preempaquetada para usar en casos de prueba donde la simplicidad y la corrección son primordiales.
WeakPointer
15
Acabo de ejecutar un punto de referencia y reflexionar. DeepEqual es 150 veces más lento que un bucle. Solo para tu información si alguien quiere usar este método en la producción.
nikdeapen 05 de
2
No compara cortes ordenados al azar con los mismos artículos :(
Hemant_Negi
55
@Hemant_Negi dos rebanadas no son iguales si tienen un orden diferente. Si desea comparar la igualdad de dos segmentos mientras ignora el orden, ordénelos y luego verifique, o mueva los elementos de un segmento a un mapa, y luego verifique que cada elemento en el otro segmento esté en el mapa. (Además, asegurarse de que tienen la misma longitud)
robbert229
3
Rob Pike (en 2011) sobre la reflexión en Go, escribiendo en el blog oficial de Go: "Es una herramienta poderosa que debe usarse con cuidado y evitarse a menos que sea estrictamente necesario" blog.golang.org/laws-of-reflection . No usaría la reflexión en el código de producción solo para comparar sectores. Esa es una función fácil de escribir. Pero tenga en cuenta que también hay una falla potencial en la respuesta elegida a esta pregunta, dependiendo del comportamiento que espere de ella: encontrará que las rebanadas que se han inicializado pero todavía están en len 0 y la tapa 0 no coinciden con las rebanadas que se han declarado pero no inicializado.
jrefior
44

Este es solo un ejemplo usando reflect.DeepEqual () que se da en la respuesta 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))

}

Resultado:

true
false

Pruébalo en Go Playground

Akavall
fuente
23

Si tiene dos []byte, compárelos con bytes . Igual . La documentación de Golang dice:

Igual devuelve un booleano que informa si a y b tienen la misma longitud y si contienen los mismos bytes. Un argumento nulo es equivalente a un segmento vacío.

Uso:

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

Esto imprimirá

true
false
KeksArmee
fuente
¿por qué es esto no superior
lurf jurv
3

Y por ahora, aquí está https://github.com/google/go-cmp que

pretende ser una alternativa más poderosa y segura reflect.DeepEqualpara comparar si dos valores son semánticamente iguales.

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
fuente
1

En caso de que esté interesado en escribir una prueba, entonces github.com/stretchr/testify/assertes su amigo.

Importe la biblioteca al principio del archivo:

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

Luego dentro de la prueba que haces:


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

El error solicitado será:

                Diff:
                --- Expected
                +++ Actual
                @@ -1,4 +1,4 @@
                 ([]int) (len=2) {
                + (int) 1,
                  (int) 2,
                - (int) 2,
                  (int) 1,
Test:           TestEquality_SomeSlice
Gabriel Furstenheim
fuente
assert.Equalutiliza internamente lo reflect.DeepEqualque puede hacer que sus pruebas se ejecuten más lentamente y, finalmente, su tubería.
Deepak Sah
@DeepakSah ¿Tiene puntos de referencia para la diferencia de rendimiento? En mi experiencia, el cuello de botella en el rendimiento de las pruebas no es igual a la afirmación, y se obtienen mensajes de gran calidad que aumentan la productividad
Gabriel Furstenheim