wei2912
wei2912

Reputation: 6609

Checking the equality of two slices

How can I check if two slices are equal, given that the operators == and != are not an option?

package main

import "fmt"

func main() {
    s1 := []int{1, 2}
    s2 := []int{1, 2}
    fmt.Println(s1 == s2)
}

This does not compile with:

invalid operation: s1 == s2 (slice can only be compared to nil)

Upvotes: 467

Views: 266664

Answers (13)

blackgreen
blackgreen

Reputation: 44647

Go 1.21 and above

The function is now in the standard library: slices.Equal.

Go 1.18 to 1.20

You cannot use == or != with slices but if you can use them with the elements then Go 1.18 has a new function in the golang.org/x/exp package to easily compare two slices, slices.Equal:

Equal reports whether two slices are equal: the same length and all elements equal. If the lengths are different, Equal returns false. Otherwise, the elements are compared in increasing index order, and the comparison stops at the first unequal pair. Floating point NaNs are not considered equal.

The slices package import path is golang.org/x/exp/slices. Code inside exp package is experimental, not yet stable. It will be moved into the standard library in Go 1.19 eventually.

Nevertheless you can use it as soon as Go 1.18 (playground)

    sliceA := []int{1, 2}
    sliceB := []int{1, 2}
    equal := slices.Equal(sliceA, sliceB)
    fmt.Println(equal) // true

    type data struct {
        num   float64
        label string
    }

    sliceC := []data{{10.99, "toy"}, {500.49, "phone"}}
    sliceD := []data{{10.99, "toy"}, {200.0, "phone"}}
    equal = slices.Equal(sliceC, sliceD)
    fmt.Println(equal) // true

If the elements of the slice don't allow == and !=, you can use slices.EqualFunc and define whatever comparator function makes sense for the element type.

Upvotes: 38

Z. Kosanovic
Z. Kosanovic

Reputation: 787

As of Go 1.21, you can use a generic function slices.Equal() from the standard library:

package main

import (
    "fmt"
    "slices"
)

func main() {
    s1 := []int{1, 4, 1, 4, 2, 1, 3, 5, 6, 2}
    s2 := []int{1, 4, 1, 4, 2, 1, 3, 5, 6, 2}

    fmt.Println(slices.Equal(s1, s2))

    s3 := []string{"foo", "bar"}
    s4 := []string{"foo", "baz"}

    fmt.Println(slices.Equal(s3, s4))
}

Playground: https://go.dev/play/p/_WwU0BSwN2P

Upvotes: 4

PRATHEESH PC
PRATHEESH PC

Reputation: 1983

Golang has introduced a package Slices with various functions useful with slices of any type. And we can use Equal function which reports whether two slices are equal.

https://cs.opensource.google/go/x/exp/+/06a737ee:slices/slices.go;l=22

// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in increasing index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[E comparable](s1, s2 []E) bool {
    if len(s1) != len(s2) {
        return false
    }
    for i := range s1 {
        if s1[i] != s2[i] {
            return false
        }
    }
    return true
}

code

package main

import (
    "fmt"

    "golang.org/x/exp/slices"
)

func main() {
    s1 := []int{1, 2}
    s2 := []int{1, 2}

    equal := slices.Equal(s1, s2)
    fmt.Println("Is Equal ? ", equal)
}

Upvotes: 1

Aditya Choudhary
Aditya Choudhary

Reputation: 19

Go language provides inbuilt support implementation for this. The reflect.DeepEqual() Function in Golang is used to check whether x and y are “deeply equal” or not. To access this function, one needs to imports the reflect package in the program.

Syntax: func DeepEqual(x, y interface{}) bool

Parameters: This function takes two parameters with value of any type, i.e. x, y.

Return Value: This function returns the boolean value.

For example: If you want to check whether map_1 and map_2 are equal or not

result := reflect.DeepEqual(map_1, map_2)

result will be true if map_1 and map_2 are equal, and result will false if map_1 and map_2 are not equal.

Upvotes: -1

mapcuk
mapcuk

Reputation: 802

There is function assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) for checking slices.

Thanks Aaron for comment, It is not obvious so I add highlight this assert requires lib "github.com/stretchr/testify/assert"

Upvotes: 0

pvlbzn
pvlbzn

Reputation: 136

To have a complete set of answers: here is a solution with generics.

func IsEqual[A comparable](a, b []A) bool {
    // Can't be equal if length differs
    if len(a) != len(b) {
        return false
    }

    // Empty arrays trivially equal
    if len(a) == 0 {
        return true
    }

    // Two pointers going towards each other at every iteration
    left := 0
    right := len(a) - 1

    for left <= right {
        if a[left] != b[left] || a[right] != b[right] {
            return false
        }

        left++
        right--
    }

    return true
}

Code uses strategy of "two pointers" which brings runtime complexity of n / 2, which is still O(n), however, twice as less steps than a linear check one-by-one.

Update: Fixed equality check bug as per @doublethink13

Upvotes: 0

Victor Deryagin
Victor Deryagin

Reputation: 12215

You should use reflect.DeepEqual()

DeepEqual is a recursive relaxation of Go's == operator.

DeepEqual reports whether x and y are “deeply equal,” defined as follows. Two values of identical type are deeply equal if one of the following cases applies. Values of distinct types are never deeply equal.

Array values are deeply equal when their corresponding elements are deeply equal.

Struct values are deeply equal if their corresponding fields, both exported and unexported, are deeply equal.

Func values are deeply equal if both are nil; otherwise they are not deeply equal.

Interface values are deeply equal if they hold deeply equal concrete values.

Map values are deeply equal if they are the same map object or if they have the same length and their corresponding keys (matched using Go equality) map to deeply equal values.

Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.

Slice values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) are not deeply equal.

Other values - numbers, bools, strings, and channels - are deeply equal if they are equal using Go's == operator.

Upvotes: 354

Gabriel Furstenheim
Gabriel Furstenheim

Reputation: 3433

In case that you are interested in writing a test, then github.com/stretchr/testify/assert is your friend.

Import the library at the very beginning of the file:

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

Then inside the test you do:


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

The error prompted will be:

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

Upvotes: 9

Wug
Wug

Reputation: 13196

Thought of a neat trick and figured I'd share.

If what you are interested in knowing is whether two slices are identical (i.e. they alias the same region of data) instead of merely equal (the value at each index of one slice equals the value in the same index of the other) then you can efficiently compare them in the following way:

foo := []int{1,3,5,7,9,11,13,15,17,19}

// these two slices are exactly identical
subslice1 := foo[3:][:4]
subslice2 := foo[:7][3:]

slicesEqual := &subslice1[0]  == &subslice2[0]   && 
               len(subslice1) == len(subslice2)

There are some caveats to this sort of comparison, in particular that you cannot compare empty slices in this way, and that the capacity of the slices isn't compared, so this "identicality" property is only really useful when reading from a slice or reslicing a strictly narrower subslice, as any attempt to grow the slice will be affected by the slices' capacity. Still, it's very useful to be able to efficiently declare, "these two huge blocks of memory are in fact the same block, yes or no."

Upvotes: 3

Stephen Weinberg
Stephen Weinberg

Reputation: 53398

You need to loop over each of the elements in the slice and test. Equality for slices is not defined. However, there is a bytes.Equal function if you are comparing values of type []byte.

func testEq(a, b []Type) bool {
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

Upvotes: 230

Akavall
Akavall

Reputation: 86168

This is just example using reflect.DeepEqual() that is given in @VictorDeryagin's answer.

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

}

Result:

true
false

Try it in Go Playground

Upvotes: 102

lk_vc
lk_vc

Reputation: 1172

And for now, here is https://github.com/google/go-cmp which

is intended to be a more powerful and safer alternative to reflect.DeepEqual for comparing whether two values are semantically equal.

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
}

Upvotes: 16

KeksArmee
KeksArmee

Reputation: 1429

If you have two []byte, compare them using bytes.Equal. The Golang documentation says:

Equal returns a boolean reporting whether a and b are the same length and contain the same bytes. A nil argument is equivalent to an empty slice.

Usage:

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

This will print

true
false

Upvotes: 61

Related Questions