ตรวจสอบความเท่าเทียมกันของสองชิ้น


274

ฉันจะตรวจสอบว่ามีสองส่วนเท่ากันได้อย่างไร


111
คำถามนี้เกี่ยวกับงานง่าย ๆ แต่ IMO เป็นคำถามจริงพร้อมคำตอบที่เฉพาะเจาะจง วิธีที่จะถูกปิดเป็น "ไม่ใช่คำถามจริง" โดยเท่าที่ฉันสามารถเห็นคนที่ฉันไม่สามารถจำได้ว่าเคยมีการใช้งานในคำถามที่ติดแท็กไปเป็นสิ่งที่เกินฉัน โดยเฉพาะ: คำถามนั้นไม่คลุมเครือสมบูรณ์มีปัญหาแคบ ๆ (แม้จะง่าย ๆ ) ไม่มีวาทศาสตร์และสามารถตอบได้อย่างแม่นยำและแม่นยำในรูปแบบปัจจุบัน ==ผู้ประกอบการที่กำหนดไว้ในไปเพียงบางชนิดดังนั้นนอกจากนี้คำถามนี้ยังเป็นหนึ่งถูกต้องตามกฎหมาย
zzzz

4
ถึงกระนั้นมันก็ไม่ได้เป็นสิ่งที่กล่าวถึงในเหตุผลที่ใกล้ชิด
Rich Churcher

9
ฮ่าฮ่าฮ่าฉันไม่อยากเชื่อเลยว่าสิ่งนี้จะถูกปิดเพราะ "ไม่ใช่คำถามจริง" 1) การบอกสิ่งที่ถูกถามไม่ใช่เรื่องยาก 2) คำถามไม่ชัดเจน / ไม่สมบูรณ์ / กว้าง / ไม่มีเหตุผล นี่เป็นการละเมิด!
weberc2

5
ดูเหมือนว่าตอนนี้มันง่ายเกินไปที่จะเข้าใจผิดปุ่ม Downvote ("ฉันคิดว่าคำถามนี้ไม่แสดงความพยายามและไม่ได้รับการถาม") ด้วยปุ่มปิด ("ฉันคิดว่ามันไม่สามารถตอบได้เนื่องจากเหตุผลดังต่อไปนี้ .. . ") อาจเป็นเพราะคะแนนโหวตปิดนั้นฟรี
Kos

3
เกิดขึ้นกับการพัฒนาใน Go และวิ่งขึ้นมาต่อต้านslice can only be compared to nilและได้สงสัยว่ามีวิธีการตรวจสอบความเท่าเทียมกันชิ้นสำนวน ... ถ้าผู้ดำเนินการความเท่าเทียมกันไม่ได้ถูกกำหนดโดยภาษาแล้วฉันคิดว่ามันสมเหตุสมผลที่จะถามวิธีที่มีประสิทธิภาพมากที่สุด เพื่อให้บรรลุมัน ไม่จำเป็นต้องปิด
คำถาม

คำตอบ:


157

คุณจำเป็นต้องวนซ้ำแต่ละองค์ประกอบในชิ้นและทดสอบ ความเท่าเทียมกันสำหรับชิ้นไม่ได้กำหนดไว้ แต่มีฟังก์ชั่นถ้าคุณกำลังเปรียบเทียบค่าประเภทbytes.Equal[]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 ยังไม่มีอะไรเหมือนยาชื่อสามัญ ซึ่งหมายความว่าคุณต้องคัดลอก n 'วางฟังก์ชั่นนี้สำหรับองค์ประกอบแต่ละประเภทที่คุณต้องการสนับสนุน นี่คือสิ่งที่เห็นได้ชัดว่าควรจัดส่งด้วยภาษา ในความเป็นจริงมันทำ (แม้ว่าจะมีเวทย์มนตร์ของการสะท้อน) และ Victor ก็ให้คำตอบ ความจริงที่ว่าสิ่งนี้ถูกเลือกไว้เหนือคำตอบนั้นและที่ได้รับการโหวตสูงกว่านั้นก็น่าคลั่ง ...
allyourcode

5
ไปเป็นภาษาที่มีแนวโน้มที่จะแนะนำไม่ได้ใช้การสะท้อนถ้าจำเป็นจริงๆ ใช่มันจำเป็นต้องทำสำหรับแต่ละประเภท แต่โดยทั่วไปไม่ใช่สิ่งที่คุณทำอยู่บ่อยๆ นอกจากนี้ reflect.DeepEqual อาจทำสิ่งที่คุณไม่คาดหวังเช่นการบอกว่าพอยน์เตอร์ที่แตกต่างกันสองตัวมีค่าเท่ากันเพราะค่าที่พวกมันชี้ไปนั้นเท่ากัน
Stephen Weinberg

2
@FiloSottile Length ได้รับการตรวจสอบล่วงหน้าวงจะมาถึงก็ต่อเมื่อความยาวแตกต่างกัน
icza

259

คุณควรใช้reflect.deepEqual ()

DeepEqual เป็นการพักผ่อนแบบวนซ้ำของโอเปอเรเตอร์ == ของโก

DeepEqual รายงานว่า x และ y เป็น“ ลึกเท่ากัน” กำหนดไว้ดังต่อไปนี้ ค่าสองประเภทที่เหมือนกันจะเท่ากันอย่างยิ่งถ้าหนึ่งในกรณีต่อไปนี้ใช้ ค่าของประเภทที่แตกต่างจะไม่เท่ากันอย่างลึกซึ้ง

ค่าอาร์เรย์มีค่าเท่ากันเมื่อองค์ประกอบที่เกี่ยวข้องมีค่าเท่ากัน

ค่าโครงสร้างจะเท่ากันอย่างยิ่งถ้าเขตข้อมูลที่สอดคล้องกันทั้งที่เอ็กซ์พอร์ตและเอ็กซ์พอร์ตนั้นมีค่าเท่ากัน

ค่าของ Func มีค่าเท่ากันถ้าทั้งคู่เป็นศูนย์ ไม่อย่างนั้นจะไม่ลึกเท่ากัน

ค่าอินเทอร์เฟซจะเท่ากันอย่างล้ำลึกหากพวกเขามีค่าที่เป็นรูปธรรมลึก

ค่าแผนที่จะเท่ากันอย่างยิ่งหากพวกเขาเป็นวัตถุแผนที่เดียวกันหรือหากพวกเขามีความยาวเท่ากันและแผนที่ที่สำคัญของพวกเขา

ค่าตัวชี้จะเท่ากันอย่างยิ่งหากพวกเขามีค่าเท่ากันโดยใช้ตัวดำเนินการ == ของ Go หรือถ้าพวกเขาชี้ไปที่ค่าที่เท่ากันอย่างลึกซึ้ง

ค่า Slice มีความลึกเท่ากันเมื่อทั้งหมดต่อไปนี้เป็นจริง: ทั้งสองเป็นศูนย์หรือไม่มีทั้งคู่พวกเขามีความยาวเท่ากันและทั้งคู่ชี้ไปที่รายการเริ่มต้นเดียวกันของอาร์เรย์ต้นแบบเดียวกัน (นั่นคือ & x [0 ] == & y [0]) หรือองค์ประกอบที่เกี่ยวข้อง (ยาวถึง) เท่ากับกัน โปรดทราบว่าส่วนที่ไม่ว่างเปล่าที่ไม่ใช่ศูนย์และชิ้นส่วนศูนย์ (ตัวอย่างเช่น [] ไบต์ {} และ [] ไบต์ (ศูนย์)) จะไม่เท่ากันอย่างลึกซึ้ง

ค่าอื่น ๆ - ตัวเลข, bools, สตริง, และแชนเนล - เท่ากันหากพวกเขาเท่ากันโดยใช้โอเปอเรเตอร์ == Go's


13
คำตอบที่มีประโยชน์มาก โดยไม่คำนึงถึงประสิทธิภาพการสะท้อนของบรรจุภัณฑ์ทั่วไปมันเป็นเรื่องที่ดีมากที่มีฟังก์ชั่นความเท่าเทียมกันระดับลึกแบบ prepackaged สำหรับใช้ในกรณีทดสอบที่ความเรียบง่ายและความถูกต้องเป็นสิ่งสำคัญยิ่ง
WeakPointer

15
ฉันวิ่งเกณฑ์มาตรฐานและไตร่ตรองช้ามากถึง 150 ครั้งช้ากว่าลูป เพียงแค่ FYI ถ้าใครต้องการใช้วิธีนี้ในการผลิต
nikdeapen

2
มันไม่ได้เปรียบเทียบชิ้นที่เรียงลำดับแบบสุ่มกับรายการเดียวกัน :(
Hemant_Negi

5
@Hemant_Negi สองชิ้นไม่เท่ากันหากมีลำดับที่ต่างกัน หากคุณต้องการเปรียบเทียบความเท่าเทียมกันของสองชิ้นในขณะที่ไม่สนใจลำดับให้เรียงแล้วตรวจสอบหรือย้ายรายการจากชิ้นหนึ่งไปยังแผนที่แล้วตรวจสอบว่าแต่ละองค์ประกอบในชิ้นอื่น ๆ อยู่ในแผนที่ (ตรวจสอบให้แน่ใจว่าพวกเขามีความยาวเท่ากัน)
robbert229

3
ร็อบหอก (ในปี 2011) การสะท้อนในไปเขียนในบล็อกอย่างเป็นทางการไป: "มันเป็นเครื่องมือที่มีประสิทธิภาพที่ควรใช้ด้วยความระมัดระวังและหลีกเลี่ยงเว้นแต่จำเป็นอย่างเคร่งครัด" blog.golang.org/laws-of-reflection ฉันจะไม่ใช้การสะท้อนในรหัสการผลิตเพียงเพื่อเปรียบเทียบสไลซ์ นั่นเป็นฟังก์ชั่นที่ใช้ง่ายในการเขียน แต่โปรดทราบว่ามีข้อบกพร่องที่อาจเกิดขึ้นในคำตอบที่เลือกสำหรับคำถามนี้เช่นกันทั้งนี้ขึ้นอยู่กับพฤติกรรมที่คุณคาดหวังจากมัน: จะพบว่ามีบางส่วนที่เริ่มต้นแล้ว แต่ยังอยู่ที่ len 0 และ cap 0 ไม่ตรงกับส่วนที่ได้รับ ประกาศแล้วแต่ยังไม่เริ่มต้น
jrefior

44

นี่เป็นเพียงตัวอย่างการใช้reflect.DeepEqual ()ที่ให้ไว้ในคำตอบ @ 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))

}

ผลลัพธ์:

true
false

ลองใช้ในสนามเด็กเล่นไป


23

หากคุณมีสอง[]byteเปรียบเทียบพวกเขาโดยใช้bytes.Equal เอกสารประกอบของ Golang พูดว่า:

เท่ากับคืนค่าบูลีนที่รายงานว่า a และ b มีความยาวเท่ากันและมีไบต์เดียวกัน อาร์กิวเมนต์ศูนย์จะเทียบเท่ากับชิ้นว่าง

การใช้งาน:

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

เหตุใดจึงไม่ด้านบน
lurf jurv

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.Equalใช้ภายในreflect.DeepEqualซึ่งอาจทำให้การทดสอบของคุณทำงานช้าลงและในที่สุดก็ไปป์ไลน์ของคุณ
Deepak Sah

@DeepakSah คุณมีเกณฑ์มาตรฐานสำหรับความแตกต่างด้านประสิทธิภาพหรือไม่? จากประสบการณ์คอขวดของฉันในการทดสอบไม่ได้อยู่ในขอบเขตที่เท่าเทียมกันและคุณจะได้รับข้อความคุณภาพที่ยอดเยี่ยมซึ่งช่วยเพิ่มประสิทธิภาพในการทำงาน
Gabriel Furstenheim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.