Home > Net >  comparing nested slices while ignoring order
comparing nested slices while ignoring order

Time:11-22

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

CodePudding user response:

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

Compare:

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

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

CodePudding user response:

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{{"bat"}, {"nat", "tan"}, {"ate", "eat", "tea"}}
  got := [][]string{{"eat", "tea", "ate"}, {"tan", "nat"}, {"bat"}}

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

    // Sorting want inners
    for _, inner := range want {
      sort.Slice(inner, func(i, j int) bool {
        return inner[i] < 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])

  • Related