두 조각이 같은지 확인


274

두 조각이 같은지 어떻게 확인할 수 있습니까?


111
질문은 실제로 간단한 작업에 관한 것이지만 IMO는 매우 구체적인 답변이있는 실제 질문입니다. 내가 볼 수있는 한, Go 태그 질문에 적극적으로 참여할 수없는 사람들이 저를 넘어서서 "진짜 질문이 아닌"것으로 폐쇄 될 수 있었던 방법은 저를 넘어선 것입니다. 구체적으로,이 질문은 모호하지 않고, 완전하고, 하나의 (단순한) 문제로 좁고, 수사적이지 않으며, 현재 형태로 정확하고 정확하게 답변 될 수 있습니다. ==운영자는 그래서 더욱,이 문제는 합법적 인 하나입니다, 일부 유형의 이동에 정의되어 있습니다.
zzzz

4
그럼에도 불구하고, 그것은 가까운 이유에서 언급 된 것들 중 어느 것도 아닙니다 ( "현재 형태로 합리적으로 대답 할 수 없습니다").
Rich Churcher

9
하하하, 나는 이것이 "진짜 질문이 아니라"는 말을 믿을 수 없다. 1) 무엇이 요청되는지 말하기는 어렵지 않습니다. 2) 질문이 모호하거나 불완전하거나 광범위하거나 부당한 것이 아닙니다. 이것은 상당히 남용입니다!
weberc2

5
현재 Closevote 버튼 ( "이 질문은 노력을 나타내지 않으며 제대로 요청되지 않았다고 생각합니다")을 Close 버튼 ( "다음 이유로 인해 답변 할 수 없다고 생각합니다.)과 오해하기가 너무 쉬운 것 같습니다. "). 마감 투표는 무료이기 때문일 수 있습니다.
코스

3
Go에서 개발하고에 반대 slice can only be compared to nil하여 일어 났고 슬라이스 평등을 확인하는 관용적 golang 방법이 있는지 궁금해했습니다 ... 평등 연산자가 언어로 정의되지 않은 경우 가장 효율적인 방법을 묻는 것이 합리적이라고 생각합니다 그것을 달성하기 위해. 질문을 닫을 필요가 없습니다
abgordon

답변:


157

슬라이스의 각 요소를 반복하고 테스트해야합니다. 슬라이스 평등이 정의되지 않았습니다. 그러나 bytes.Equaltype의 값을 비교 하는 경우 함수가 있습니다 []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
제안 : for i, v := range a { if v != b[i] { return false } }.
zzzz

19
@zzzz 조심하십시오, 이것은 다른 길이에서 실패합니다.
FiloSottile

2
요소 유형이 ==를 지원하지 않으면 작동하지 않습니다. 또한 IIUC, Go에는 제네릭과 같은 것이 없습니다. 즉, 지원하려는 각 요소 유형에 대해이 기능을 붙여 넣기해야합니다. 이것은 분명히 언어와 함께 제공되어야하는 것입니다. 실제로는 (반영의 마법에도 불구하고), Victor는 그 답을 제공합니다. 이 답변 위에 선택되고 더 많은 투표를 한 사실은 단순히 화를
내는 것입니다

5
언어는 꼭 필요한 경우가 아니면 리플렉션을 사용하지 않는 것이 좋습니다. 예, 각 유형마다 수행해야하지만 일반적으로 어쨌든 자주하는 일은 아닙니다. 또한 reflect.DeepEqual은 두 개의 서로 다른 포인터가 동일하다고 말하는 것과 같이 예상하지 않은 작업을 수행 할 수 있습니다.
Stephen Weinberg

2
@FiloSottile 길이는 미리 확인되며 길이가 다른 경우에만 루프에 도달합니다.
icza

259

reflect.DeepEqual ()을 사용해야합니다.

DeepEqual은 Go = 연산자의 재귀 완화입니다.

DeepEqual은 x와 y가 "깊게 같은지"보고하며 다음과 같이 정의됩니다. 다음 경우 중 하나에 해당하는 경우 동일한 유형의 두 값이 완전히 동일합니다. 고유 한 유형의 값은 절대로 동일하지 않습니다.

배열 값은 해당 요소가 매우 같을 때 매우 같습니다.

반출 및 반출되지 않은 해당 필드가 완전히 동일한 경우 구조 값은 매우 동일합니다.

둘 다 0이 아닌 경우 함수 값은 매우 같습니다. 그렇지 않으면 그들은 깊이 평등하지 않습니다.

인터페이스 값이 매우 동일한 콘크리트 값을 보유하는 경우 인터페이스 값이 동일합니다.

맵 값이 동일한 맵 객체이거나 길이가 동일하고 해당 키 (Go equality를 사용하여 일치)가 동일한 값을 갖는 경우 맵 값은 매우 동일합니다.

Go의 == 연산자를 사용하여 포인터 값이 같거나 값이 매우 같으면 포인터 값이 매우 같습니다.

다음 값이 모두 참이면 슬라이스 값이 완전히 동일합니다.이 값은 모두 0이거나 0이 아닌 값이며 길이가 같으며 동일한 기본 배열의 동일한 초기 항목을 가리 킵니다 (즉, & x [0 ] == & y [0]) 또는 해당 요소 (최대 길이)는 매우 같습니다. 0이 아닌 빈 슬라이스와 0이 아닌 슬라이스 (예 : [] byte {} 및 [] byte (nil))는 서로 동일하지 않습니다.

다른 값 (숫자, 부울, 문자열 및 채널)은 Go의 == 연산자를 사용하여 같으면 깊이 같습니다.


13
매우 유용한 답변입니다. 일반적인 패키지 성능에 관계없이 단순성과 정확성이 가장 중요한 테스트 사례에 사용하기 위해 사전 패키징 된 딥 동등 기능을 갖는 것이 매우 좋습니다.
WeakPointer

15
방금 벤치 마크를 실행하고 반영했습니다 .DeepEqual은 루프보다 150 배 느립니다. 누군가 생산에서이 방법을 사용하려면 참고하십시오.
nikdeapen

2
무작위로 정렬 된 슬라이스를 동일한 항목과 비교하지 않습니다. (
Hemant_Negi

5
@Hemant_Negi 두 슬라이스가 순서가 다르면 동일하지 않습니다. 순서를 무시하면서 두 슬라이스의 동등성을 비교하려면 정렬 한 다음 항목을 한 슬라이스에서 맵으로 확인하거나 이동 한 다음 다른 슬라이스의 각 요소가 맵에 있는지 확인하십시오. (추가로 길이가 동일해야 함)
robbert229 2016 년

3
Go의 공식적인 블로그 블로그에 글을 남긴 Rob Pike (2011 년) : "이 도구는주의해서 사용해야하며 반드시 필요한 경우가 아니면 피해야하는 강력한 도구" blog.golang.org/laws-of-reflection . 프로덕션 코드에서 리플렉션을 사용하여 슬라이스를 비교하지는 않습니다. 작성하기 쉬운 기능입니다. 그러나이 질문에 대한 선택된 답변에는 예상되는 동작에 따라 잠재적 인 결함이 있음을 유의하십시오. 초기화되었지만 여전히 len 0에 있고 조각 0은 조각과 일치하지 않습니다. 선언되었지만 초기화되지 않았습니다.
jrefior

44

이것은 @VictorDeryagin의 답변에 제공된 reflect.DeepEqual () 을 사용하는 예제 입니다.

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

}

결과:

true
false

Go Playground 에서 사용해보십시오


23

두 개가 있으면 bytes.Equal을[]byte 사용하여 비교 하십시오 . Golang 설명서에는 다음과 같은 내용이 있습니다.

같음 a와 b의 길이가 같고 바이트가 같은지 여부를보고하는 부울 값을 반환합니다. nil 인수는 빈 슬라이스와 같습니다.

용법:

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

이것은 인쇄됩니다

true
false

이유는 없습니다 최고입니다
jurv lurf

3

그리고 지금은 https://github.com/google/go-cmp 입니다.

reflect.DeepEqual두 값이 의미 적으로 동일한 지 비교 하기 위한 보다 강력하고 안전한 대안 입니다.

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

시험 작성에 관심이 있다면 github.com/stretchr/testify/assert친구입니다.

파일 맨 처음에 라이브러리를 가져옵니다.

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

그런 다음 테스트 내에서 수행하십시오.


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

오류 메시지는 다음과 같습니다.

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

assert.Equalreflect.DeepEqual테스트를 느리게 실행하고 결국에는 파이프 라인을 테스트 할 수 있도록 내부적으로 사용 합니다.
Deepak Sah

@DeepakSah 성능 차이에 대한 벤치 마크가 있습니까? 테스트에 내 경험의 성능 병목에서 동일한 어설 아닌, 당신은 생산성 향상을 가지고 좋은 품질의 메시지를 얻을
가브리엘 Furstenheim
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.