Checking the equality of two slices

GoGo Reflect

Go Problem Overview


How can I check if two slices are equal?

Go Solutions


Solution 1 - Go

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.

Solution 2 - Go

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
}

Solution 3 - Go

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

Solution 4 - Go

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

Solution 5 - Go

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
}

Solution 6 - Go

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

Solution 7 - Go

You cannot use == or != with slices but if you can use them with the elements then Go 1.18 has a new function to easily compare two slices, slices.Equal (https://pkg.go.dev/golang.org/x/exp/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.
func Equal[E comparable](s1, s2 []E) bool

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

Nevertheless you can use it as soon as Go 1.18, https://go.dev/play/p/QEdoEuYNTlD?v=gotip

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

	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)

If the elements of the slice don't allow == and !=, you can use slices.EqualFunc (https://pkg.go.dev/golang.org/x/exp/slices#EqualFunc).

Solution 8 - Go

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."

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionwei2912View Question on Stackoverflow
Solution 1 - GoVictor DeryaginView Answer on Stackoverflow
Solution 2 - GoStephen WeinbergView Answer on Stackoverflow
Solution 3 - GoAkavallView Answer on Stackoverflow
Solution 4 - GoKeksArmeeView Answer on Stackoverflow
Solution 5 - Golk_vcView Answer on Stackoverflow
Solution 6 - GoGabriel FurstenheimView Answer on Stackoverflow
Solution 7 - GoMarco JärvinenView Answer on Stackoverflow
Solution 8 - GoWugView Answer on Stackoverflow