diff --git a/go.sum b/go.sum index 12890ad84..b00930f70 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,8 @@ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= diff --git a/slices/slices.go b/slices/slices.go index cff0cd49e..51c9dec61 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)] } + +// Intersection finds elements that are present in both slices, returning new slice without duplicates +func Intersection[E comparable](s1, s2 []E) []E { + var result []E + s2len := len(s2) + s1len := len(s1) + if s1len == 0 || s2len == 0 { + return result + } + 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..3bb471775 100644 --- a/slices/slices_test.go +++ b/slices/slices_test.go @@ -767,3 +767,80 @@ func BenchmarkReplace(b *testing.B) { } } + +func TestIntersection(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{}, + }, + { + name: "duplicates int", + s: []int{2, 4, 1}, + v: []int{1, 3, 1}, + want: []int{1}, + }, + { + name: "regular use", + s: []int{1, 2, 3}, + v: []int{3, 4, 5}, + want: []int{3}, + }, + { + name: "nil value", + s: nil, + v: nil, + want: nil, + }, + { + name: "different size", + s: []int{1, 5}, + v: []int{5, 10, 25}, + want: []int{5}, + }, + } + strTypeCases := []struct { + name string + s, v []string + want []string + }{ + { + name: "duplicates string", + s: []string{"a", "b", "c"}, + v: []string{"b", "b", "z"}, + want: []string{"b"}, + }, + { + name: "contain substring", + s: []string{"abc", "h", "i"}, + v: []string{"ab", "g", "z"}, + want: []string{}, + }, + } + for _, test := range intTypeCases { + t.Run(test.name, func(tt *testing.T) { + if got := Intersection(test.s, test.v); !Equal(got, test.want) { + tt.Errorf("Intersection(%v) = %v, want %v", test.s, got, test.want) + } + }) + } + for _, test := range strTypeCases { + t.Run(test.name, func(tt *testing.T) { + if got := Intersection(test.s, test.v); !Equal(got, test.want) { + tt.Errorf("Intersection(%v) = %v, want %v", test.s, got, test.want) + } + }) + } +}