İki dilimin eşitliğini kontrol etme


274

İki dilimin eşit olup olmadığını nasıl kontrol edebilirim?


111
Soru gerçekten basit bir görevle ilgili, ancak IMO çok özel bir cevapla gerçek bir soru. Gördüğüm kadarıyla, Go etiketli sorularda hiç aktif olduğunu hatırlayamadığım insanlar tarafından nasıl "gerçek bir soru değil" olarak kapatılabileceği aşıldı. Özellikle: soru belirsiz, tam, tek (basit olsa da) bir soruna dar, retorik değildir ve mevcut haliyle tam ve doğru olarak cevaplanabilir. ==Operatör böylece dahası, bu soru da meşru bir tanesidir, sadece bazı türleri için Go tanımlanmıştır.
zzzz

4
Yine de, yakın sebepten bahsedenlerin hiçbiri değildir ("mevcut haliyle makul bir şekilde cevaplanamaz").
Rich Churcher

9
Hahaha, bunun "gerçek bir soru" için kapandığına inanamıyorum. 1) Ne sorulduğunu söylemek zor değil. 2) Soru belirsiz / eksik / geniş / mantıksız değil. Bu oldukça kötüye kullanım!
weberc2

5
Görünüşe göre Downvote düğmesine ("Bu soru çaba göstermiyor ve iyi sorulmuyor") hata vermenin çok kolay olduğu anlaşılıyor Kapat düğmesi ("Aşağıdaki nedenden dolayı cevaplanamayacağını düşünüyorum ..) . "). Yakın oylar ücretsiz olduğu için olabilir.
Kos

3
Go'da geliştiği ve karşı karşıya slice can only be compared to nilkaldığı ve dilim eşitliğini kontrol etmenin deyimsel bir golang yolu olup olmadığını merak ediyordum ... eşitlik operatörü dil tarafından tanımlanmadıysa, en etkili yolu sormayı makul buluyorum başarmak için. Sorunun kapatılmasına gerek yoktu
abgordon

Yanıtlar:


157

Dilim ve öğelerin her biri üzerinde döngü ve test gerekir. Dilimler için eşitlik tanımlanmamıştır. Ancak, bytes.Equaltür değerlerini karşılaştırıyorsanız bir işlev vardır []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
Öneri: for i, v := range a { if v != b[i] { return false } }.
zzzz

19
@zzzz Dikkatli olun, bu farklı uzunluklarda başarısız olacaktır.
FiloSottile

2
Öğe türü == desteklemiyorsa bu çalışmaz. Ayrıca, IIUC, Go'nun jenerik gibi bir şeyi yoktur. Bu, desteklemek istediğiniz her öğe türü için bu işlevi kopyalayıp yapıştırmanız gerektiği anlamına gelir. Bu açıkça dil ile birlikte gönderilmesi gereken bir şey. Aslında, (yansıtma büyüsü de olsa) yapar ve Victor cevap verir. Bunun bu cevabın üzerinde seçilmesi ve daha yüksek oyu
alması

5
Bir dil olarak git, kesinlikle gerekli olmadığı sürece yansıma kullanmamanızı tavsiye eder. Evet, her tür için yapılması gerekir, ancak genellikle sık sık yaptığınız bir şey değildir. Ayrıca, refl.DeepEqual beklemediğiniz bir şey yapabilir, örneğin iki farklı işaretçi eşittir çünkü işaret ettikleri değerler eşittir.
Stephen Weinberg

2
@FiloSottile Uzunluk önceden kontrol edilir, döngüye yalnızca uzunluklar farklıysa ulaşılır.
icza

259

Refl.DeepEqual () öğesini kullanmalısınız

DeepEqual, Go'nun == operatörünün yinelemeli bir gevşemesidir.

DeepEqual, x ve y'nin “derinden eşit” olup olmadığını bildirir ve aşağıdaki gibi tanımlanır. Aşağıdaki durumlardan biri geçerliyse, aynı türdeki iki değer tamamen eşittir. Farklı türlerin değerleri asla derinden eşit değildir.

Dizi değerleri, karşılık gelen öğeleri derin eşit olduğunda eşittir.

Yapı değerleri, hem dışa aktarılan hem de dışa aktarılan karşılık gelen alanları derinden eşitse, derinden eşittir.

Her ikisi de sıfırsa işlev değerleri derinden eşittir; aksi halde derinden eşit değildirler.

Arayüz değerleri, derinden eşit beton değerlerine sahiplerse derinden eşittir.

Eşleme değerleri aynı eşleme nesnesi olmaları veya aynı uzunluklara sahip olmaları ve karşılık gelen anahtarları (Git eşitliği kullanılarak eşleştirildikleri) eşleme değerleriyle eşleştirmek için eşleme değerleri çok eşittir.

İşaretçi değerleri, Go'nun == işleci kullanılarak eşitse veya derinden eşit değerlere işaret ediyorsa eşittir.

Aşağıdakilerin tümü doğru olduğunda dilim değerleri derinden eşittir: her ikisi de nil veya her ikisi de nil değil, aynı uzunluğa sahipler ve ya aynı temel dizinin aynı ilk girişini gösteriyorlar (yani, & x [0) ] == & y [0]) veya karşılık gelen öğeleri (en fazla) derinden eşittir. Sıfır olmayan boş bir dilim ile sıfır dilim (örneğin, [] byte {} ve [] byte (nil)) derinden eşit değildir.

Diğer değerler - sayılar, bools, dizeler ve kanallar - Go'nun == işleci kullanılarak eşitlerse derinden eşittir.


13
Çok faydalı bir cevap. Genel yansıma paketi performansından bağımsız olarak, sadeliğin ve doğruluğun çok önemli olduğu test durumlarında kullanılmak üzere hazır ambalajlı derin eşitlik fonksiyonuna sahip olmak çok güzel.
WeakPointer

15
Ben sadece bir kıyaslama koştum ve yansıttım.DeepEqual bir döngüden 150 kat daha yavaş. Bu yöntemi üretimde kullanmak isteyen varsa sadece FYI.
nikdeapen

2
Rastgele sıralanan dilimleri aynı öğelerle karşılaştırmaz :(
Hemant_Negi

5
@Hemant_Negi iki dilim farklı bir sıraya sahipse eşit değildir. Sırayı göz ardı ederken iki dilimin eşitliğini karşılaştırmak istiyorsanız, bunları sıralayın ve ardından öğeleri bir dilimden bir haritaya taşıyın ve ardından diğer dilimdeki her öğenin haritada olduğunu kontrol edin. (ayrıca aynı uzunlukta olduklarından emin olun)
robbert229 13:17

3
Rob Pike (2011'de) Go'daki yansıması üzerine, resmi Go blogunda yazıyor: " Dikkatle kullanılması ve kesinlikle gerekli olmadıkça kaçınılması gereken güçlü bir araçtır" blog.golang.org/laws-of-reflection . Dilimleri karşılaştırmak için üretim kodundaki yansımayı kullanmam. Bu yazması kolay bir işlev. Ancak, bu sorunun hangi cevabından beklediğinize bağlı olarak, bu sorunun seçilen cevabında da potansiyel bir kusur olduğuna dikkat edin: Başlatılmış, ancak len 0 ve başlık 0'da olan dilimlerin, beyan edilmiş ancak başlatılmamış.
jrefior

44

Bu sadece @ VictorDeryagin'in cevabında verilen refl.DeepEqual () kullanarak bir örnektir .

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

}

Sonuç:

true
false

Go Playground'da deneyin


23

İki tane varsa []byte, bayt kullanarak karşılaştırın . Golang belgeleri şöyle diyor:

Eşit, a ve b'nin aynı uzunlukta olup olmadığını ve aynı baytları içerip içermediğini bildiren bir boole bildirimi döndürür. Nil argümanı boş bir dilim ile eşdeğerdir.

Kullanımı:

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

Bu yazdırılacak

true
false

neden bu üst değil
lurf jurv

3

Ve şimdi, burada https://github.com/google/go-cmp hangi

reflect.DeepEqualiki değerin anlamsal olarak eşit olup olmadığını karşılaştırmak için daha güçlü ve daha güvenli bir alternatif olması amaçlanmıştır .

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

Bir test yazmakla ilgileniyorsanız, o zaman github.com/stretchr/testify/assert arkadaşınız olur.

Dosyanın en başında kütüphaneyi içe aktarın:

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

Sonra testin içinde şunları yaparsınız:


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

İstenen hata şöyle olacaktır:

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

assert.Equaldahili olarak kullanır, reflect.DeepEqualbu da testlerinizin daha yavaş çalışmasını sağlayabilir ve sonuçta boru hattınız.
Deepak Sah

@DeepakSah Performans farkı için referanslarınız var mı? Deneyimlerime göre, testlerdeki performans darboğazı, eşdeğerde değildir ve üretkenliği artıran mükemmel kalitede mesajlar alırsınız
Gabriel Furstenheim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.