From ad777bc877a948d85f3483163062f41a83cbc3eb Mon Sep 17 00:00:00 2001 From: dudaodong Date: Mon, 27 Dec 2021 19:47:45 +0800 Subject: [PATCH] feat: add Intersection, Union, Without func for slice/slice.go --- slice/slice.go | 104 ++++++++++++++++++++++++++++++++++++++++---- slice/slice_test.go | 62 +++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 10 deletions(-) diff --git a/slice/slice.go b/slice/slice.go index d112e09..99376e2 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -379,22 +379,28 @@ func Unique(slice interface{}) interface{} { return slice } - var res []interface{} + var temp []interface{} + len := 0 for i := 0; i < sv.Len(); i++ { v := sv.Index(i).Interface() - flag := true - for j := range res { - if v == res[j] { - flag = false + skip := true + for j := range temp { + if v == temp[j] { + skip = false break } } - if flag { - res = append(res, v) + if skip { + temp = append(temp, v) + len++ } } - return res + res := reflect.MakeSlice(sv.Type(), len, len) + for i := 0; i < len; i++ { + res.Index(i).Set(reflect.ValueOf(temp[i])) + } + return res.Interface() // if use map filter, the result slice element order is random, not same as origin slice //mp := make(map[interface{}]bool) @@ -411,6 +417,66 @@ func Unique(slice interface{}) interface{} { } +// Union creates an slice of unique values, in order, from all given slices. using == for equality comparisons. +func Union(slices ...interface{}) interface{} { + if len(slices) == 0 { + return nil + } + // append all slices, then unique it + var allSlice []interface{} + len := 0 + for i := range slices { + sv := sliceValue(slices[i]) + len += sv.Len() + for j := 0; j < sv.Len(); j++ { + v := sv.Index(j).Interface() + allSlice = append(allSlice, v) + } + } + + sv := sliceValue(slices[0]) + res := reflect.MakeSlice(sv.Type(), len, len) + for i := 0; i < len; i++ { + res.Index(i).Set(reflect.ValueOf(allSlice[i])) + } + + return Unique(res.Interface()) +} + +// Intersection creates an slice of unique values that included by all slices. +func Intersection(slices ...interface{}) interface{} { + if len(slices) == 0 { + return nil + } + + reduceFunc := func(index int, slice1, slice2 interface{}) interface{} { + set := make([]interface{}, 0) + hash := make(map[interface{}]bool) + + sv1 := reflect.ValueOf(slice1) + for i := 0; i < sv1.Len(); i++ { + v := sv1.Index(i).Interface() + hash[v] = true + } + + sv2 := reflect.ValueOf(slice2) + for i := 0; i < sv2.Len(); i++ { + el := sv2.Index(i).Interface() + if _, found := hash[el]; found { + set = append(set, el) + } + } + res := reflect.MakeSlice(sv1.Type(), len(set), len(set)) + for i := 0; i < len(set); i++ { + res.Index(i).Set(reflect.ValueOf(set[i])) + } + return res.Interface() + } + + res := Reduce(slices, reduceFunc, nil) + return Union(res) +} + // ReverseSlice return slice of element order is reversed to the given slice func ReverseSlice(slice interface{}) { v := sliceValue(slice) @@ -474,3 +540,25 @@ func SortByField(slice interface{}, field string, sortType ...string) error { } return nil } + +// Without creates an array excluding all given values +func Without(slice interface{}, values ...interface{}) interface{} { + sv := sliceValue(slice) + if sv.Len() == 0 { + return slice + } + var indexes []int + for i := 0; i < sv.Len(); i++ { + v := sv.Index(i).Interface() + if !Contain(values, v) { + indexes = append(indexes, i) + } + } + + res := reflect.MakeSlice(sv.Type(), len(indexes), len(indexes)) + for i := range indexes { + res.Index(i).Set(sv.Index(indexes[i])) + } + + return res.Interface() +} diff --git a/slice/slice_test.go b/slice/slice_test.go index 044b0c2..7b6a549 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -395,7 +395,7 @@ func updateByIndex(t *testing.T, test interface{}, index int, value, expected in func TestUnique(t *testing.T) { t1 := []int{1, 2, 2, 3} e1 := []int{1, 2, 3} - r1, _ := IntSlice(Unique(t1)) + r1 := Unique(t1) if !reflect.DeepEqual(r1, e1) { utils.LogFailedTestInfo(t, "Unique", t1, e1, r1) t.FailNow() @@ -403,13 +403,60 @@ func TestUnique(t *testing.T) { t2 := []string{"a", "a", "b", "c"} e2 := []string{"a", "b", "c"} - r2 := StringSlice(Unique(t2)) + r2 := Unique(t2) if !reflect.DeepEqual(r2, e2) { utils.LogFailedTestInfo(t, "Unique", t2, e2, r2) t.FailNow() } } +func TestUnion(t *testing.T) { + s1 := []int{1, 3, 4, 6} + s2 := []int{1, 2, 5, 6} + s3 := []int{0, 4, 5, 7} + + expected1 := []int{1, 3, 4, 6, 2, 5, 0, 7} + res1 := Union(s1, s2, s3) + if !reflect.DeepEqual(res1, expected1) { + utils.LogFailedTestInfo(t, "Union", s1, expected1, res1) + t.FailNow() + } + + expected2 := []int{1, 3, 4, 6} + res2 := Union(s1) + if !reflect.DeepEqual(res2, expected2) { + utils.LogFailedTestInfo(t, "Union", s1, expected2, res2) + t.FailNow() + } +} + +func TestIntersection(t *testing.T) { + s1 := []int{1, 2, 2, 3} + s2 := []int{1, 2, 3, 4} + s3 := []int{0, 2, 3, 5, 6} + s4 := []int{0, 5, 6} + + expected := [][]int{ + {2, 3}, + {1, 2, 3}, + {1, 2, 3}, + {}, + } + res := []interface{}{ + Intersection(s1, s2, s3), + Intersection(s1, s2), + Intersection(s1), + Intersection(s1, s4), + } + for i := 0; i < len(res); i++ { + if !reflect.DeepEqual(res[i], expected[i]) { + utils.LogFailedTestInfo(t, "Intersection", "Intersection", expected[i], res[i]) + t.FailNow() + } + } + +} + func TestReverseSlice(t *testing.T) { s1 := []int{1, 2, 3, 4, 5} e1 := []int{5, 4, 3, 2, 1} @@ -469,3 +516,14 @@ func TestSortByField(t *testing.T) { } } + +func TestWithout(t *testing.T) { + s := []int{1, 2, 3, 4, 5} + expected := []int{3, 4, 5} + res := Without(s, 1, 2) + + if !reflect.DeepEqual(res, expected) { + utils.LogFailedTestInfo(t, "Without", s, expected, res) + t.FailNow() + } +}