Reputation: 6609
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
Reputation: 44647
The function is now in the standard library: slices.Equal
.
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
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
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
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
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
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
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
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
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
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
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
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
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