Kiểm tra sự bằng nhau của hai lát


274

Làm thế nào tôi có thể kiểm tra nếu hai lát bằng nhau?


111
Câu hỏi thực sự là về một nhiệm vụ đơn giản, nhưng IMO nó là một câu hỏi thực sự, với một câu trả lời rất cụ thể. Làm thế nào nó có thể bị đóng vì "không phải là một câu hỏi thực sự", theo như tôi có thể thấy, những người tôi không thể nhớ là đã từng hoạt động trong các câu hỏi được gắn thẻ Go, nằm ngoài tôi. Cụ thể: câu hỏi không mơ hồ, đầy đủ, hẹp đối với một vấn đề (dù đơn giản), không khoa trương và có thể được trả lời chính xác và chính xác ở dạng hiện tại. Các ==nhà điều hành được xác định tại Gò chỉ một số loại, vì vậy hơn nữa, câu hỏi này cũng là một trong những hợp pháp.
zzzz

4
Tuy nhiên, đó không phải là bất kỳ điều gì được đề cập trong lý do gần gũi ("không thể được trả lời một cách hợp lý ở dạng hiện tại").
giàu có

9
Hahaha, tôi không thể tin rằng điều này đã bị đóng cửa vì "không phải là một câu hỏi thực sự". 1) Không khó để nói những gì đang được hỏi. 2) Câu hỏi không mơ hồ / không đầy đủ / rộng / không hợp lý. Đây là một lạm dụng!
weberc2

5
Có vẻ như hiện tại quá dễ để nhầm nút Downvote ("Tôi nghĩ câu hỏi này không thể hiện nỗ lực và không được hỏi nhiều") với nút Đóng ("Tôi nghĩ rằng nó không thể được trả lời vì lý do sau .. . "). Có thể là do Đóng phiếu là miễn phí.
Kos

3
Đã xảy ra khi phát triển trong Go và chạy lên chống lại slice can only be compared to nil, và tự hỏi liệu có một cách golang thành ngữ nào để kiểm tra sự bình đẳng lát cắt ... nếu toán tử đẳng thức không được xác định bởi ngôn ngữ, thì tôi thấy hợp lý khi hỏi cách hiệu quả nhất để hoàn thành nó Câu hỏi không cần phải đóng
abgordon

Câu trả lời:


157

Bạn cần lặp qua từng phần tử trong lát và kiểm tra. Bình đẳng cho các lát không được xác định. Tuy nhiên, có một bytes.Equalhàm nếu bạn đang so sánh các giá trị của loại []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
Gợi ý : for i, v := range a { if v != b[i] { return false } }.
zzzz

19
@zzzz Cẩn thận, điều này sẽ thất bại trên các độ dài khác nhau.
FiloSottile

2
Điều này không hoạt động nếu loại phần tử không hỗ trợ ==. Ngoài ra, IIUC, Go không có bất cứ thứ gì như thuốc generic. Điều này có nghĩa là bạn phải sao chép n 'dán chức năng này cho từng loại phần tử mà bạn muốn hỗ trợ. Đây rõ ràng là một cái gì đó nên gửi với ngôn ngữ. Trong thực tế, nó làm (mặc dù với phép thuật phản chiếu), và Victor cung cấp câu trả lời. Thực tế là điều này được chọn ở trên câu trả lời đó, và được đánh giá cao hơn chỉ đơn giản là điên rồ ...
allyourcode

5
Đi như một ngôn ngữ có xu hướng khuyên không nên sử dụng sự phản chiếu trừ khi thực sự cần thiết. Vâng, nó sẽ cần phải được thực hiện cho từng loại nhưng nó thường không phải là thứ bạn thường làm. Ngoài ra, Refl.DeepEqual có thể làm điều gì đó mà bạn không mong đợi, chẳng hạn như nói hai con trỏ khác nhau bằng nhau vì các giá trị mà chúng trỏ đến bằng nhau.
Stephen Weinberg

2
@FiloSottile Chiều dài được kiểm tra trước, vòng lặp chỉ đạt được nếu độ dài khác nhau.
icza

259

Bạn nên sử dụng Refl.DeepEqual ()

DeepEqual là một thư giãn đệ quy của toán tử Go's ==.

DeepEqual báo cáo xem x và y có phải là sâu bằng nhau hay không, được định nghĩa như sau. Hai giá trị cùng loại là bằng nhau nếu áp dụng một trong các trường hợp sau. Giá trị của các loại khác nhau không bao giờ bằng nhau sâu sắc.

Các giá trị mảng bằng nhau sâu khi các phần tử tương ứng của chúng bằng nhau sâu.

Các giá trị cấu trúc là bằng nhau sâu sắc nếu các trường tương ứng của chúng, cả xuất và không xuất, đều bằng nhau sâu sắc.

Giá trị Func bằng nhau sâu nếu cả hai đều không; nếu không thì chúng không bằng nhau sâu sắc.

Các giá trị giao diện là bằng nhau sâu sắc nếu chúng giữ các giá trị cụ thể sâu bằng nhau.

Các giá trị bản đồ hoàn toàn bằng nhau nếu chúng là cùng một đối tượng bản đồ hoặc nếu chúng có cùng độ dài và các khóa tương ứng của chúng (được khớp bằng cách sử dụng đẳng thức Go) với các giá trị bằng nhau sâu.

Các giá trị con trỏ hoàn toàn bằng nhau nếu chúng bằng nhau khi sử dụng toán tử Go's == hoặc nếu chúng trỏ đến các giá trị bằng nhau sâu.

Các giá trị lát cắt bằng nhau sâu sắc khi tất cả các giá trị sau là đúng: chúng đều là số không hoặc cả số không, chúng có cùng độ dài và chúng trỏ đến cùng một mục nhập ban đầu của cùng một mảng bên dưới (nghĩa là, & x [0 ] == & y [0]) hoặc các yếu tố tương ứng của chúng (tối đa) dài bằng nhau. Lưu ý rằng một lát trống không phải là con số không và một lát cắt không (ví dụ: [] byte {} và [] byte (nil)) không bằng nhau.

Các giá trị khác - số, số, chuỗi và kênh - hoàn toàn bằng nhau nếu chúng bằng nhau khi sử dụng toán tử Go's ==.


13
Một câu trả lời rất hữu ích. Bất kể hiệu suất gói phản ánh chung là gì, rất tốt khi có hàm bình đẳng sâu đóng gói sẵn để sử dụng trong các trường hợp thử nghiệm trong đó tính đơn giản và chính xác là tối quan trọng.
WeakPulum

15
Tôi vừa chạy một điểm chuẩn và phản ánh.DeepEqual chậm hơn 150 lần so với vòng lặp. Chỉ cần FYI nếu bất cứ ai muốn sử dụng phương pháp này trong sản xuất.
nikdeapen

2
Nó không so sánh các lát được sắp xếp ngẫu nhiên với các mặt hàng tương tự :(
Hemant_Negi

5
@Hemant_Negi hai lát không bằng nhau nếu chúng có thứ tự khác nhau. Nếu bạn muốn so sánh sự bằng nhau của hai lát trong khi bỏ qua thứ tự thì hãy sắp xếp chúng và sau đó kiểm tra hoặc di chuyển các mục từ một lát vào bản đồ, sau đó kiểm tra xem từng phần tử trên lát kia có trong bản đồ không. (ngoài ra hãy chắc chắn rằng chúng có cùng chiều dài)
robbert229

3
Rob Pike (năm 2011) về phản ánh trong Go, viết trên blog chính thức của Go: "Đó là một công cụ mạnh mẽ nên được sử dụng cẩn thận và tránh trừ khi rất cần thiết" blog.golang.org/laws-of-reflection . Tôi sẽ không sử dụng sự phản chiếu trong mã sản xuất chỉ để so sánh các lát. Đó là một chức năng dễ viết. Nhưng lưu ý rằng cũng có một lỗ hổng tiềm năng trong câu trả lời được chọn cho câu hỏi này, tùy thuộc vào hành vi mà bạn mong đợi từ nó: nó sẽ thấy rằng các lát đã được khởi tạo nhưng vẫn ở len 0 và nắp 0 không khớp với các lát đã được khớp khai báo nhưng không khởi tạo.
jrefior

44

Đây chỉ là ví dụ sử dụng Refl.DeepEqual () được đưa ra trong câu trả lời của @ 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))

}

Kết quả:

true
false

Hãy thử nó trong Sân chơi Go


23

Nếu bạn có hai []byte, so sánh chúng bằng byte.Equal . Tài liệu Golang nói:

Bằng nhau trả về một báo cáo boolean cho dù a và b có cùng độ dài và chứa cùng một byte. Một đối số không tương đương với một lát trống.

Sử dụng:

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

Cái này sẽ in

true
false

Tại sao điều này không phải là hàng đầu
lurf judv

3

Và bây giờ, đây là https://github.com/google/go-cmp

được dự định là một sự thay thế mạnh mẽ hơn và an toàn hơn để reflect.DeepEqualso sánh xem hai giá trị có bằng nhau về mặt ngữ nghĩa hay không.

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

Trong trường hợp bạn quan tâm đến việc viết một bài kiểm tra, thì đó github.com/stretchr/testify/assertlà bạn của bạn.

Nhập thư viện ở phần đầu của tệp:

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

Sau đó, bên trong bài kiểm tra bạn làm:


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

Lỗi được nhắc sẽ là:

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

assert.Equalsử dụng nội bộ reflect.DeepEqualcó thể làm cho các bài kiểm tra của bạn chạy chậm hơn và cuối cùng là đường ống của bạn.
Deepak Sah

@DeepakSah Bạn có điểm chuẩn cho sự khác biệt hiệu suất? Theo kinh nghiệm của tôi, tắc nghẽn hiệu suất trong các thử nghiệm không phải là bằng nhau và bạn nhận được thông điệp chất lượng tuyệt vời giúp tăng năng suất
Gabriel Furstenheim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.