2つのスライスが等しいかどうかを確認するにはどうすればよいですか?
9 に答える
Reflect.DeepEqual()を使用する必要があります
DeepEqualは、Goの==演算子の再帰的な緩和です。
DeepEqualは、xとyが「完全に等しい」かどうかを報告します。これは次のように定義されます。次のいずれかの場合に当てはまる場合、同じタイプの2つの値は完全に等しくなります。異なるタイプの値が完全に等しくなることはありません。
対応する要素が完全に等しい場合、配列値は非常に等しくなります。
構造体の値は、エクスポートされたフィールドとエクスポートされていないフィールドの両方の対応するフィールドが完全に等しい場合、非常に等しくなります。
両方がnilの場合、Func値は完全に等しくなります。そうでなければ、それらは深く等しくありません。
インターフェース値は、具体的な値が非常に等しい場合、非常に等しくなります。
マップ値は、それらが同じマップオブジェクトであるか、同じ長さであり、対応するキー(Goの等式を使用して一致)が非常に等しい値にマップされる場合、完全に等しくなります。
Goの==演算子を使用して等しい場合、またはポインター値が非常に等しい値を指している場合、ポインター値は非常に等しくなります。
スライス値は、次のすべてが当てはまる場合に完全に等しくなります。両方がnilまたは両方が非nilであり、長さが同じであり、同じ基になる配列の同じ初期エントリを指している(つまり、&x [0 ] ==&y [0])またはそれらの対応する要素(長さまで)は完全に等しい。nil以外の空のスライスとnilスライス(たとえば、[] byte{}と[]byte(nil))は完全に等しくないことに注意してください。
Goの==演算子を使用して等しい場合、他の値(数値、ブール、文字列、およびチャネル)は完全に等しくなります。
スライス内の各要素をループしてテストする必要があります。スライスの等式は定義されていません。ただし、bytes.Equal
タイプの値を比較する場合は関数があります[]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
}
これは、@ VictorDeryaginの回答で示されているreflect.DeepEqual()を使用した単なる例です。
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))
}
結果:
true
false
GoPlaygroundでお試しください
2つある場合は、 bytes.Equal[]byte
を使用してそれらを比較します。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
そして今のところ、ここにhttps://github.com/google/go-cmpがあります
reflect.DeepEqual
2つの値が意味的に等しいかどうかを比較するための、より強力で安全な代替手段となることを目的としています。
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
}
あなたがテストを書くことに興味があるなら、それ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
きちんとしたトリックを考えて、私が共有したいと思いました。
単に等しい(一方のスライスの各インデックスの値が他方の同じインデックスの値と等しい)のではなく、2つのスライスが同一である(つまり、データの同じ領域をエイリアスする)かどうかを知りたい場合は、次のことができます。次の方法で効率的に比較します。
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)
この種の比較にはいくつかの注意点があります。特に、この方法では空のスライスを比較できないこと、およびスライスの容量が比較されないことです。したがって、この「同一性」プロパティは、スライスから読み取る場合にのみ非常に役立ちます。スライスを拡大しようとするとスライスの容量の影響を受けるため、厳密に狭いサブスライスを再スライスします。それでも、「これらの2つの巨大なメモリブロックは、実際には同じブロックであるかどうかにかかわらず」と効率的に宣言できると非常に便利です。
==
スライスと一緒に使用することはできません!=
が、要素と一緒に使用できる場合は、この問題https://github.com/golang/go/issues/45955は、2つのスライスを簡単に比較するための新しい関数を示しています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 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
パッケージのslices
インポートパスはgolang.org/x/exp/slicesです。exp
パッケージ内のコードは実験的なものであり、まだ安定していません。Go1.19で標準ライブラリに昇格することができます。
それでも、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)
==
スライスの要素でとが許可されていない場合は!=
、を使用できますslices.EqualFunc
。
actual
ソートされたスライスと比較する前に、スライスをソートできexpected
ます。
func TestEquality_SomeSlice(t *testing.T) {
expected := []int{1, 2, 3, 4}
actual := []int{2, 1, 4, 3}
sort.Slice(actual, func(i, j int) bool {
return actual[i] < actual[j]
})
assert.Equal(t, expected, actual)
}