From 7bcdf798c3df3c3f524d333c0f76e89ed1f44c36 Mon Sep 17 00:00:00 2001 From: Vicente Cheng Date: Wed, 13 Dec 2023 15:58:31 +0800 Subject: [PATCH] slice: add some Slice functions - SliceCompare - SliceDedupe Signed-off-by: Vicente Cheng --- go.mod | 1 + go.sum | 2 ++ slice.go | 45 +++++++++++++++++++++++++++++ slice_test.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 slice.go create mode 100644 slice_test.go diff --git a/go.mod b/go.mod index e6b33fe..b3ada28 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/godbus/dbus/v5 v5.0.4 github.com/sirupsen/logrus v1.9.2 github.com/stretchr/testify v1.7.0 + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index aa265da..1d758d3 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/slice.go b/slice.go new file mode 100644 index 0000000..7bfee1d --- /dev/null +++ b/slice.go @@ -0,0 +1,45 @@ +package gocommon + +import "golang.org/x/exp/slices" + +// SliceCompare compares two slices and returns true if they are the same. +func SliceCompare[T comparable](x, y []T) bool { + if len(x) == 0 && len(y) == 0 { + return true + } + if len(x) != len(y) { + return false + } + + yCpy := make([]T, len(y)) + copy(yCpy, y) + for _, xItem := range x { + found := false + for id, yItem := range yCpy { + if xItem == yItem { + yCpy = slices.Delete(yCpy, id, id+1) + found = true + break + } + } + if !found { + return false + } + } + return true +} + +// SliceDedupe removes duplicated items and return a non-deplucated items slice. +func SliceDedupe[T comparable](x []T) []T { + if len(x) == 0 { + return x + } + + result := make([]T, 0) + for _, item := range x { + if !slices.Contains(result, item) { + result = append(result, item) + } + } + return result +} diff --git a/slice_test.go b/slice_test.go new file mode 100644 index 0000000..63bdf21 --- /dev/null +++ b/slice_test.go @@ -0,0 +1,79 @@ +package gocommon + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type SliceFuncs struct { + suite.Suite +} + +func TestSliceFuncs(t *testing.T) { + suite.Run(t, new(SliceFuncs)) +} + +func (s *SliceFuncs) SetupSuite() { + // you could do something here before all tests +} + +func (s *SliceFuncs) TestSliceCompareInt() { + a := []int{1, 2, 3} + b := []int{3, 2, 1} + c := []int{1, 2, 3, 4} + d := []int{} + e := []int{} + f := []int{1, 1, 2} + g := []int{1, 2, 2} + fCpy := []int{1, 1, 2} + gCpy := []int{1, 2, 2} + + s.Equal(true, SliceCompare(a, b), "SliceCompare should return true") + s.Equal(false, SliceCompare(a, c), "SliceCompare should return false") + s.Equal(true, SliceCompare(d, e), "SliceCompare should return true") + s.Equal(false, SliceCompare(f, g), "SliceCompare should return false") + s.Equal(f, fCpy, "original slice should not change.") + s.Equal(g, gCpy, "original slice should not change.") + +} + +func (s *SliceFuncs) TestSliceCompareString() { + a := []string{"a", "b", "c"} + b := []string{"b", "c", "a"} + c := []string{"a", "b", "c", "d"} + d := []string{} + e := []string{} + f := []string{"a", "a", "b"} + g := []string{"a", "b", "b"} + fCpy := []string{"a", "a", "b"} + gCpy := []string{"a", "b", "b"} + + s.Equal(true, SliceCompare(a, b), "SliceCompare should return true") + s.Equal(false, SliceCompare(a, c), "SliceCompare should return false") + s.Equal(true, SliceCompare(d, e), "SliceCompare should return true") + s.Equal(false, SliceCompare(f, g), "SliceCompare should return false") + s.Equal(f, fCpy, "original slice should not change.") + s.Equal(g, gCpy, "original slice should not change.") +} + +func (s *SliceFuncs) TestSliceDedupeInt() { + a := []int{1, 1, 2, 2, 3, 3} + b := []int{1, 2, 3, 4, 5, 6} + c := []int{1, 2, 3, 3, 4} + + require.Equal(s.T(), []int{1, 2, 3}, SliceDedupe(a), "SliceDedupe should return the same slice with {1, 2, 3}") + require.Equal(s.T(), []int{1, 2, 3, 4, 5, 6}, SliceDedupe(b), "SliceDedupe should return the same slice with {1, 2, 3, 4, 5, 6}") + require.Equal(s.T(), []int{1, 2, 3, 4}, SliceDedupe(c), "SliceDedupe should return the same slice with {1, 2, 3, 4}") +} + +func (s *SliceFuncs) TestSliceDedupeString() { + a := []string{"foo", "bar", "bar", "foo", "roll", "roll"} + b := []string{"apple", "book", "clock", "duck", "escape", "field"} + c := []string{"foo", "bar", "roll", "roll", "desk"} + + require.Equal(s.T(), []string{"foo", "bar", "roll"}, SliceDedupe(a), "SliceDedupe should return the same slice with {foo, bar, roll}") + require.Equal(s.T(), []string{"apple", "book", "clock", "duck", "escape", "field"}, SliceDedupe(b), "SliceDedupe should return the same slice with {apple, book, clock, duck, escape, field}") + require.Equal(s.T(), []string{"foo", "bar", "roll", "desk"}, SliceDedupe(c), "SliceDedupe should return the same slice with {foo, bar, roll, desk}") +}