检查两个切片的相等性


274

如何检查两个切片是否相等?


111
这个问题确实是关于一个简单的任务的,但是IMO是一个真正的问题,有一个非常具体的答案。据我所知,如何使我无法回忆起一直活跃在Go标签问题中的人们以“不是一个真正的问题”来解决这个问题超出了我的范围。具体来说:该问题不是模棱两可,完整,狭窄到单个(尽管很简单)问题,没有修辞,可以以当前的形式准确,准确地回答。该==运营商在去定义只为某些类型的,所以此外,这个问题也是合法的。
zzzz

4
不过,这并不是最直接的原因(“无法以当前形式合理地回答”)。
Rich Churcher

9
哈哈哈,我不敢相信这是因为“不是一个真正的问题”而结束的。1)知道要问的内容并不难。2)问题不是模棱两可/不完整/广泛/不合理。这是一种滥用!
weberc2 2013年

5
似乎现在很容易将Downvote按钮(“我认为这个问题没有显示出来,也没有很好地询问”)与关闭按钮(“我认为由于以下原因无法回答。”)。 。”)。可能是因为接近投票是免费的。
科斯2015年

3
碰巧是在Go中开发并遇到了问题slice can only be compared to nil,并且想知道是否存在惯用的golang方法来检查切片是否相等...如果该语言未定义相等运算符,那么我觉得提出最有效的方法是合理的完成它。问题不需要结束
abgordon '16

Answers:


157

您需要遍历切片中的每个元素并进行测试。未定义切片的相等性。但是,bytes.Equal如果要比较type的值,则有一个函数[]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 2013年

19
@zzzz小心,这将在不同的长度上失败。
FiloSottile 2014年

2
如果元素类型不支持==,则此方法不起作用。另外,IIUC,Go没有类似泛型的东西。这意味着您必须为要支持的每种元素类型复制n'粘贴此函数。这显然是语言应附带的东西。实际上,它确实做到了(尽管具有反射的魔力),而Victor提供了答案。事实是,在此答案上方选择了这个选项,并对其进行了更高程度的投票,这简直令人发疯……
allyourcode 2015年

5
除非绝对必要,否则按语言进行搜索通常建议不要使用反射。是的,每种类型都需要完成此操作,但是总之,您通常不会经常这样做。另外,reflect.DeepEqual可能会执行您不期望的操作,例如说两个不同的指针相等,因为它们指向的值相等。
斯蒂芬·温伯格2015年

2
预先检查@FiloSottile Length,仅在长度不同时才到达循环。
icza 2015年

259

您应该使用reflect.DeepEqual()

DeepEqual是Go的==运算符的递归松弛。

DeepEqual报告x和y是否“深度相等”,定义如下。如果满足以下情况之一,则两个相同类型的值将完全相等。不同类型的值永远不会完全相等。

当数组的对应元素深度相等时,数组值深度相等。

如果结构的值对应的字段(导出的和未导出的)都非常相等,则该值非常相等。

如果两者均为零,则Func值非常相等;否则,它们就不会完全平等。

如果接口值具有完全相等的具体值,则它们是高度相等的。

如果映射值是相同的映射对象,或者它们具有相同的长度,并且它们的对应键(使用Go相等性进行匹配)映射为深度相等的值,则它们是深度相等的。

如果指针值使用Go的==运算符相等,或者它们指向深度相等的值,则它们的深度相等。

当满足以下所有条件时,切片值将完全相等:它们均为nil或均为非nil,它们具有相同的长度,并且它们指向同一基础数组的相同初始条目(即&x [0 ] ==&y [0])或它们相应的元素(最大长度)相等。请注意,非nil空片和nil片(例如[] byte {}和[] byte(nil))并不完全相等。

如果使用Go的==运算符,其他值(数字,布尔值,字符串和通道)将完全相等。


13
一个非常有用的答案。不管总体上反映软件包的性能如何,都有一个预包装的深度相等函数用于在简单性和正确性至关重要的测试用例中非常好。
WeakPointer

15
我只是运行了一个基准并进行了反思。DeepEqual比循环慢150倍。如果有人想在生产中使用此方法,则仅供参考。
nikdeapen

2
它不会比较具有相同项目的随机排序切片:(
Hemant_Negi

5
@Hemant_Negi如果两个切片的顺序不同,则它们不相等。如果要在忽略顺序的同时比较两个切片的相等性,请对其进行排序,然后检查,或将一个切片中的项目移动到地图中,然后检查另一个切片上的每个元素是否在地图中。(另外确保它们具有相同的长度)
robbert229

3
Rob Pike(2011年)谈到 Go中的反思时,在Go官方博客中写道:“这是一个功能强大的工具,应谨慎使用,除非绝对必要,否则应避免使用。” blog.golang.org/laws-of-reflection。我不会在生产代码中仅使用反射来比较切片。这是一个易于编写的函数。但是请注意,根据您期望的行为,在选择此问题的答案时也存在潜在的缺陷:它将发现已初始化但仍为len 0和cap 0的切片与已被切片的切片不匹配。声明但未初始化。
jrefior


23

如果有两个[]byte,则使用bytes.Equal比较它们。Golang文档说:

Equal返回一个布尔值,报告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

为什么这不是顶峰
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您是否有性能差异基准?以我的经验,测试中的性能瓶颈并不
完全相同
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.