From f72bc6b98244ebe0af54b9f7bd2323c61e42fba7 Mon Sep 17 00:00:00 2001 From: Aleksander Dudek Date: Mon, 19 Dec 2022 21:48:46 +0100 Subject: [PATCH 1/2] intersection implementation in slices module --- go.sum | 6 ---- slices/slices.go | 12 ++++++++ slices/slices_test.go | 65 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) 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..6f7913772 100644 --- a/slices/slices.go +++ b/slices/slices.go @@ -256,3 +256,15 @@ 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 + for i := 0; i < len(s1); i++ { + element := s1[i] + if Contains(s2, element) && !Contains(result, element) { + result = append(result, element) + } + } + return result +} diff --git a/slices/slices_test.go b/slices/slices_test.go index 1d9ffd2f3..106f928ba 100644 --- a/slices/slices_test.go +++ b/slices/slices_test.go @@ -767,3 +767,68 @@ 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}, + }, + } + 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) + } + }) + } +} From 549e8bfbe3cd3c06fb40d61abb9a557cb4c5122e Mon Sep 17 00:00:00 2001 From: Aleksander Dudek Date: Tue, 20 Dec 2022 07:36:01 +0100 Subject: [PATCH 2/2] performance bust for intersection implementation --- slices/slices.go | 14 ++++++++++++-- slices/slices_test.go | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/slices/slices.go b/slices/slices.go index 6f7913772..51c9dec61 100644 --- a/slices/slices.go +++ b/slices/slices.go @@ -260,9 +260,19 @@ func Clip[S ~[]E, E any](s S) 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 - for i := 0; i < len(s1); i++ { + 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 Contains(s2, element) && !Contains(result, element) { + if _, ok := s2Map[element]; ok { result = append(result, element) } } diff --git a/slices/slices_test.go b/slices/slices_test.go index 106f928ba..3bb471775 100644 --- a/slices/slices_test.go +++ b/slices/slices_test.go @@ -798,6 +798,18 @@ func TestIntersection(t *testing.T) { 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