From 33ca1be5a6da4d6f136d55f7d9d96d109c45fa00 Mon Sep 17 00:00:00 2001 From: cui fliter Date: Sat, 25 Feb 2023 17:13:21 +0800 Subject: [PATCH] slices: add Difference function Signed-off-by: cui fliter --- slices/slices.go | 22 +++++++++++++ slices/slices_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/slices/slices.go b/slices/slices.go index cff0cd49e..64fca4f93 100644 --- a/slices/slices.go +++ b/slices/slices.go @@ -256,3 +256,25 @@ func Grow[S ~[]E, E any](s S, n int) S { func Clip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] } + +// Difference finds elements that exist in slice 1 but not in slice 2, and there may be duplicate elements in the returned slice. +func Difference[E comparable](s1, s2 []E) []E { + var result []E + s2len := len(s2) + s1len := len(s1) + if s2len == 0 { + return s1 + } + s2Map := make(map[E]bool, s2len) + for i := 0; i < s2len; i++ { + el := s2[i] + s2Map[el] = true + } + for i := 0; i < s1len; i++ { + element := s1[i] + if _, ok := s2Map[element]; !ok { + result = append(result, element) + } + } + return result +} diff --git a/slices/slices_test.go b/slices/slices_test.go index 1d9ffd2f3..deee16b07 100644 --- a/slices/slices_test.go +++ b/slices/slices_test.go @@ -767,3 +767,80 @@ func BenchmarkReplace(b *testing.B) { } } + +func TestDifference(t *testing.T) { + intTypeCases := []struct { + name string + s, v []int + want []int + }{ + { + name: "empty first slice", + s: []int{}, + v: []int{1, 4}, + want: []int{}, + }, + { + name: "empty second slice", + s: []int{1, 3}, + v: []int{}, + want: []int{1, 3}, + }, + { + name: "duplicates int", + s: []int{2, 4, 1, 2}, + v: []int{1, 3, 1}, + want: []int{2, 4, 2}, + }, + { + name: "regular use", + s: []int{1, 2, 3}, + v: []int{3, 4, 5}, + want: []int{1, 2}, + }, + { + name: "nil value", + s: nil, + v: nil, + want: nil, + }, + { + name: "different size", + s: []int{1, 5}, + v: []int{5, 10, 25}, + want: []int{1}, + }, + } + strTypeCases := []struct { + name string + s, v []string + want []string + }{ + { + name: "duplicates string", + s: []string{"a", "b", "c"}, + v: []string{"b", "b", "z"}, + want: []string{"a", "c"}, + }, + { + name: "contain substring", + s: []string{"abc", "h", "i"}, + v: []string{"ab", "g", "z"}, + want: []string{"abc", "h", "i"}, + }, + } + for _, test := range intTypeCases { + t.Run(test.name, func(tt *testing.T) { + if got := Difference(test.s, test.v); !Equal(got, test.want) { + tt.Errorf("Difference(%v) = %v, want %v", test.s, got, test.want) + } + }) + } + for _, test := range strTypeCases { + t.Run(test.name, func(tt *testing.T) { + if got := Difference(test.s, test.v); !Equal(got, test.want) { + tt.Errorf("Difference(%v) = %v, want %v", test.s, got, test.want) + } + }) + } +}