检查没有订单的切片上的相等性

XXX*_*XXX 6 equality go slice

我试图找到一个解决方案来检查2片中的相等性.不幸的是,我发现的答案要求切片中的值处于相同的顺序.例如,http: //play.golang.org/p/yV0q1_u3xR将等式计算为false.
我想要一个可以[]string{"a","b","c"} == []string{"b","a","c"}评估的解决方案true.
更多示例
[]string{"a","a","c"} == []string{"c","a","c"} >>> false
[]string{"z","z","x"} == []string{"x","z","z"}>>>true

Joh*_*röm 17

您可以cmp.Diff与以下一起使用cmpopts.SortSlices

less := func(a, b string) bool { return a < b }
equalIgnoreOrder := cmp.Diff(x, y, cmpopts.SortSlices(less)) == ""
Run Code Online (Sandbox Code Playgroud)

这是在Go Playground上运行的完整示例:

package main

import (
    "fmt"

    "github.com/google/go-cmp/cmp"
    "github.com/google/go-cmp/cmp/cmpopts"
)

func main() {
    x := []string{"a", "b", "c"}
    y := []string{"a", "c", "b"}
    
    less := func(a, b string) bool { return a < b }
    equalIgnoreOrder := cmp.Diff(x, y, cmpopts.SortSlices(less)) == ""
    fmt.Println(equalIgnoreOrder) // prints "true"

}
Run Code Online (Sandbox Code Playgroud)

  • 如果你只想要一个布尔结果,你不应该使用 `cmp.Equal` 而不是 `cmp.Diff` 吗? (2认同)

Raf*_*ypa 13

就像adrianlzt在他的回答中所写的那样,可以使用assert.ElementsMatchfrom testify的实现来实现这一点。但是,当您需要的只是比较的 bool 结果时,重用实际的 testify 模块而不是复制该代码怎么样?testify 中的实现旨在用于测试代码,并且通常带有testing.T参数。

事实证明,ElementsMatch 可以很容易地在测试代码之外使用。它所需要的只是一个带有ErrorF方法的接口的虚拟实现:

type dummyt struct{}

func (t dummyt) Errorf(string, ...interface{}) {}

func elementsMatch(listA, listB interface{}) bool {
    return assert.ElementsMatch(dummyt{}, listA, listB)
}
Run Code Online (Sandbox Code Playgroud)

或者在The Go Playground上测试它,它是我根据 adrianlzt 的示例改编的。


sbe*_*rry 8

这是一个替代解决方案,虽然可能有点冗长:

func sameStringSlice(x, y []string) bool {
    if len(x) != len(y) {
        return false
    }
    // create a map of string -> int
    diff := make(map[string]int, len(x))
    for _, _x := range x {
        // 0 value for int is 0, so just increment a counter for the string
        diff[_x]++
    }
    for _, _y := range y {
        // If the string _y is not in diff bail out early
        if _, ok := diff[_y]; !ok {
            return false
        }
        diff[_y] -= 1
        if diff[_y] == 0 {
            delete(diff, _y)
        }
    }
    if len(diff) == 0 {
        return true
    }
    return false
}
Run Code Online (Sandbox Code Playgroud)

试试吧 Go Playground


adr*_*lzt 8

概括testify ElementsMatch的代码,比较任何类型的对象的解决方案(在示例中[]map[string]string):

https://play.golang.org/p/xUS2ngrUWUl


Aka*_*all 7

其他答案有更好的时间复杂度O(N)VS (O(N log(N)),这是我的答案,也是我的解决方案将占用更多的内存,如果在片元素被频繁地重复,但我想补充它,因为我觉得这是应该做的最直接的方式它:

package main

import (
    "fmt"
    "sort"
    "reflect"
)

func array_sorted_equal(a, b []string) bool {
    if len(a) != len(b) {return false }

    a_copy := make([]string, len(a))
    b_copy := make([]string, len(b))

    copy(a_copy, a)
    copy(b_copy, b)

    sort.Strings(a_copy)
    sort.Strings(b_copy)

    return reflect.DeepEqual(a_copy, b_copy)
}

func main() {
    a := []string {"a", "a", "c"}
    b := []string {"c", "a", "c"}
    c := []string {"z","z","x"} 
    d := []string {"x","z","z"}


    fmt.Println( array_sorted_equal(a, b))
    fmt.Println( array_sorted_equal(c, d))

}
Run Code Online (Sandbox Code Playgroud)

结果:

false
true
Run Code Online (Sandbox Code Playgroud)


Dim*_*rov 5

我认为最简单的方法是将每个数组/切片中的元素映射到它们的出现次数,然后比较这些映射:

func main() {
    x := []string{"a","b","c"}
    y := []string{"c","b","a"}

    xMap := make(map[string]int)
    yMap := make(map[string]int)

    for _, xElem := range x {
        xMap[xElem]++
    }
    for _, yElem := range y {
        yMap[yElem]++
    }

    for xMapKey, xMapVal := range xMap {
        if yMap[xMapKey] != xMapVal {
            return false
        }
    }
    return true
}
Run Code Online (Sandbox Code Playgroud)

您需要添加一些额外的注意事项,例如,如果阵列/切片包含不同类型或不同长度的元素,则会短路。