Skip to content

Commit 33ca1be

Browse files
committed
slices: add Difference function
Signed-off-by: cui fliter <[email protected]>
1 parent c95f2b4 commit 33ca1be

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

slices/slices.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,25 @@ func Grow[S ~[]E, E any](s S, n int) S {
256256
func Clip[S ~[]E, E any](s S) S {
257257
return s[:len(s):len(s)]
258258
}
259+
260+
// Difference finds elements that exist in slice 1 but not in slice 2, and there may be duplicate elements in the returned slice.
261+
func Difference[E comparable](s1, s2 []E) []E {
262+
var result []E
263+
s2len := len(s2)
264+
s1len := len(s1)
265+
if s2len == 0 {
266+
return s1
267+
}
268+
s2Map := make(map[E]bool, s2len)
269+
for i := 0; i < s2len; i++ {
270+
el := s2[i]
271+
s2Map[el] = true
272+
}
273+
for i := 0; i < s1len; i++ {
274+
element := s1[i]
275+
if _, ok := s2Map[element]; !ok {
276+
result = append(result, element)
277+
}
278+
}
279+
return result
280+
}

slices/slices_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,3 +767,80 @@ func BenchmarkReplace(b *testing.B) {
767767
}
768768

769769
}
770+
771+
func TestDifference(t *testing.T) {
772+
intTypeCases := []struct {
773+
name string
774+
s, v []int
775+
want []int
776+
}{
777+
{
778+
name: "empty first slice",
779+
s: []int{},
780+
v: []int{1, 4},
781+
want: []int{},
782+
},
783+
{
784+
name: "empty second slice",
785+
s: []int{1, 3},
786+
v: []int{},
787+
want: []int{1, 3},
788+
},
789+
{
790+
name: "duplicates int",
791+
s: []int{2, 4, 1, 2},
792+
v: []int{1, 3, 1},
793+
want: []int{2, 4, 2},
794+
},
795+
{
796+
name: "regular use",
797+
s: []int{1, 2, 3},
798+
v: []int{3, 4, 5},
799+
want: []int{1, 2},
800+
},
801+
{
802+
name: "nil value",
803+
s: nil,
804+
v: nil,
805+
want: nil,
806+
},
807+
{
808+
name: "different size",
809+
s: []int{1, 5},
810+
v: []int{5, 10, 25},
811+
want: []int{1},
812+
},
813+
}
814+
strTypeCases := []struct {
815+
name string
816+
s, v []string
817+
want []string
818+
}{
819+
{
820+
name: "duplicates string",
821+
s: []string{"a", "b", "c"},
822+
v: []string{"b", "b", "z"},
823+
want: []string{"a", "c"},
824+
},
825+
{
826+
name: "contain substring",
827+
s: []string{"abc", "h", "i"},
828+
v: []string{"ab", "g", "z"},
829+
want: []string{"abc", "h", "i"},
830+
},
831+
}
832+
for _, test := range intTypeCases {
833+
t.Run(test.name, func(tt *testing.T) {
834+
if got := Difference(test.s, test.v); !Equal(got, test.want) {
835+
tt.Errorf("Difference(%v) = %v, want %v", test.s, got, test.want)
836+
}
837+
})
838+
}
839+
for _, test := range strTypeCases {
840+
t.Run(test.name, func(tt *testing.T) {
841+
if got := Difference(test.s, test.v); !Equal(got, test.want) {
842+
tt.Errorf("Difference(%v) = %v, want %v", test.s, got, test.want)
843+
}
844+
})
845+
}
846+
}

0 commit comments

Comments
 (0)