From 6f035f710ee52e8f0311ea4574bb6191320cfd2f Mon Sep 17 00:00:00 2001 From: dudaodong Date: Sun, 23 Jan 2022 14:27:37 +0800 Subject: [PATCH] feat: add DifferenceBy func --- slice/slice.go | 39 +++++++++++++++++++++++++++++++++++++++ slice/slice_test.go | 11 +++++++++++ 2 files changed, 50 insertions(+) diff --git a/slice/slice.go b/slice/slice.go index 0e978a6..9f0b7fb 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -164,6 +164,45 @@ func Difference(slice1, slice2 interface{}) interface{} { return res.Interface() } +// DifferenceBy it accepts iteratee which is invoked for each element of slice +// and values to generate the criterion by which they're compared. +// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy, +// the iterateeFn function signature should be func(index int, value interface{}) interface{}. +func DifferenceBy(slice interface{}, comparedSlice interface{}, iterateeFn interface{}) interface{} { + sv := sliceValue(slice) + smv := sliceValue(comparedSlice) + fn := functionValue(iterateeFn) + + elemType := sv.Type().Elem() + if checkSliceCallbackFuncSignature(fn, elemType, nil) { + panic("function param should be of type func(" + elemType.String() + ")" + elemType.String()) + } + + slice1 := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len()) + for i := 0; i < sv.Len(); i++ { + slice1.Index(i).Set(fn.Call([]reflect.Value{reflect.ValueOf(i), sv.Index(i)})[0]) + } + + slice2 := reflect.MakeSlice(smv.Type(), smv.Len(), smv.Len()) + for i := 0; i < smv.Len(); i++ { + slice2.Index(i).Set(fn.Call([]reflect.Value{reflect.ValueOf(i), smv.Index(i)})[0]) + } + + sliceAfterMap := slice1.Interface() + comparedSliceAfterMap := slice2.Interface() + + res := reflect.MakeSlice(sv.Type(), 0, 0) + sm := sliceValue(sliceAfterMap) + for i := 0; i < sm.Len(); i++ { + item := sm.Index(i).Interface() + if !Contain(comparedSliceAfterMap, item) { + res = reflect.Append(res, sv.Index(i)) + } + } + + return res.Interface() +} + // Every return true if all of the values in the slice pass the predicate function. // The function signature should be func(index int, value interface{}) bool . func Every(slice, function interface{}) bool { diff --git a/slice/slice_test.go b/slice/slice_test.go index 82dbb61..eec492d 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -439,6 +439,17 @@ func TestDifference(t *testing.T) { assert.Equal([]int{1, 2, 3}, Difference(s1, s2)) } +func TestDifferenceBy(t *testing.T) { + assert := internal.NewAssert(t, "TestDifferenceBy") + + s1 := []int{1, 2, 3, 4, 5} //after add one: 2 3 4 5 6 + s2 := []int{3, 4, 5} //after add one: 4 5 6 + addOne := func(i int, v int) int { + return v + 1 + } + assert.Equal([]int{1, 2}, DifferenceBy(s1, s2, addOne)) +} + func TestSortByFielDesc(t *testing.T) { assert := internal.NewAssert(t, "TestWithout")