比较嵌套切片并忽略顺序

huangapple go评论77阅读模式
英文:

comparing nested slices while ignoring order

问题

在一个测试函数中,有一种情况需要比较嵌套切片。假设我有两个变量如下:

want := [][]string{{"bat"},{"nat","tan"},{"ate","eat","tea"}}
got := [][]string{{"eat","tea","ate"},{"tan","nat"},{"bat"}}

如何比较它们?

首先,我尝试使用reflect.DeepEqual,但是结果是错误的。我还尝试了go-cmp

t.Run(tt.name, func(t *testing.T) {
	opt := cmpopts.SortSlices(func (a, b []int) bool {
		// 不确定要写什么
	})

	if got := groupAnagrams(tt.args.strs); !cmp.Equal(got, tt.want, opt) {
		t.Errorf("groupAnagrams() = %v, want %v", got, tt.want)
	}
})
英文:

In a test function, there is a case where nested slices should be compared.
Say I have two varibles like the following:

want := [][]string{{"bat"},{"nat","tan"},{"ate","eat","tea"}}
got := [][]string{{"eat","tea","ate"},{"tan","nat"},{"bat"}}

How can compare them?

First, I used reflect.DeepEqual which was wrong, I also tried go-cmp:

	t.Run(tt.name, func(t *testing.T) {
		opt := cmpopts.SortSlices(func (a, b []int) bool {
			// not sure what to write
		})

		if got := groupAnagrams(tt.args.strs); !cmp.Equal(got, tt.want, opt) {
			t.Errorf("groupAnagrams() = %v, want %v", got, tt.want)
		}
	})

答案1

得分: 1

对内部切片进行排序:

for _, s := range want { sort.Strings(s) }
for _, s := range got { sort.Strings(s) }

对外部切片进行排序:

sortOuter(want)
sortOuter(got)

其中sortOuter是一个函数:

func sortOuter(s [][]string) {
	sort.Slice(s, func(a, b int) bool {
		sa := s[a]
		sb := s[b]
		n := len(sa)
		if n > len(sb) {
			n = len(sb)
		}
		for i := 0; i < n; i++ {
			if sa[i] != sb[i] {
				return sa[i] < sb[i]
			}
		}
		return len(sa) < len(sb)
	})
}

比较:

fmt.Println(reflect.DeepEqual(got, want))

https://go.dev/play/p/SjN8gLmotjd

英文:

Sort the inner slices:

for _, s := range want { sort.Strings(s) }
for _, s := range got { sort.Strings(s) }

Sort the outer slices:

sortOuter(want)
sortOuter(got)

where sortOuter is a the function:

func sortOuter(s [][]string) {
	sort.Slice(s, func(a, b int) bool {
		sa := s[a]
		sb := s[b]
		n := len(sa)
		if n &gt; len(sb) {
			n = len(sb)
		}
		for i := 0; i &lt; n; i++ {
			if sa[i] != sb[i] {
				return sa[i] &lt; sb[i]
			}
		}
		return len(sa) &lt; len(sb)
	})
}

Compare:

fmt.Println(reflect.DeepEqual(got, want))

https://go.dev/play/p/SjN8gLmotjd

答案2

得分: 1

你可以使用sort.Slice对内部切片进行排序,并使用testifyassert.ElementsMatch检查外部切片是否相等:

func TestXxx(t *testing.T) {
  // 切片
  want := [][]string{{"bat"}, {"nat", "tan"}, {"ate", "eat", "tea"}}
  got := [][]string{{"eat", "tea", "ate"}, {"tan", "nat"}, {"bat"}}

  // 运行测试
  t.Run("test", func(t *testing.T) {
    // 对got的内部切片进行排序
    for _, inner := range got {
      sort.Slice(inner, func(i, j int) bool {
        return inner[i] < inner[j]
      })
    }

    // 对want的内部切片进行排序
    for _, inner := range want {
      sort.Slice(inner, func(i, j int) bool {
        return inner[i] < inner[j]
      })
    }

    // 匹配
    assert.ElementsMatch(t, got, want)
  })
}

ElementsMatch:

ElementsMatch断言指定的listA(数组、切片...)与指定的listB(数组、切片...)相等,忽略元素的顺序。如果有重复元素,则两个列表中每个元素的出现次数应该相同。

assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])

英文:

You can sort inner slices using sort.Slice as below and check if outer slices are equal using testify assert.ElementsMatch:

func TestXxx(t *testing.T) {
  // Slices
  want := [][]string{{&quot;bat&quot;}, {&quot;nat&quot;, &quot;tan&quot;}, {&quot;ate&quot;, &quot;eat&quot;, &quot;tea&quot;}}
  got := [][]string{{&quot;eat&quot;, &quot;tea&quot;, &quot;ate&quot;}, {&quot;tan&quot;, &quot;nat&quot;}, {&quot;bat&quot;}}

  // Running tests
  t.Run(&quot;test&quot;, func(t *testing.T) {
    // Sorting got inners
    for _, inner := range got {
      sort.Slice(inner, func(i, j int) bool {
        return inner[i] &lt; inner[j]
      })
    }

    // Sorting want inners
    for _, inner := range want {
      sort.Slice(inner, func(i, j int) bool {
        return inner[i] &lt; inner[j]
      })
    }

    // Match
    assert.ElementsMatch(t, got, want)
  })
}

ElementsMatch:

> ElementsMatch asserts that the specified listA(array, slice...) is equal to specified listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, the number of appearances of each of them in both lists should match.

assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])

huangapple
  • 本文由 发表于 2022年11月20日 09:55:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/74505134.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定