diff --git a/slice/slice.go b/slice/slice.go index 33b8efc..fa9983b 100644 --- a/slice/slice.go +++ b/slice/slice.go @@ -726,6 +726,31 @@ func Unique(slice interface{}) interface{} { } +// UniqueBy call iteratee func with every item of slice, then remove duplicated. +// The iteratee function signature should be func(value interface{}) interface{}. +func UniqueBy(slice, iteratee interface{}) interface{} { + sv := sliceValue(slice) + fn := functionValue(iteratee) + + // elemType := sv.Type().Elem() + // if !checkCallbackFuncSignature2(fn, elemType, elemType) { + // panic("iteratee function signature should be of type func(" + elemType.String() + ")" + elemType.String()) + // } + + if sv.Len() == 0 { + return slice + } + + res := reflect.MakeSlice(sv.Type(), sv.Len(), sv.Len()) + + for i := 0; i < sv.Len(); i++ { + val := fn.Call([]reflect.Value{sv.Index(i)})[0] + res.Index(i).Set(val) + } + + return Unique(res.Interface()) +} + // Union creates a slice of unique values, in order, from all given slices. using == for equality comparisons. func Union(slices ...interface{}) interface{} { if len(slices) == 0 { diff --git a/slice/slice_test.go b/slice/slice_test.go index 7256f40..c801be1 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -418,6 +418,15 @@ func TestUnique(t *testing.T) { assert.Equal([]string{"a", "b", "c"}, Unique([]string{"a", "a", "b", "c"})) } +func TestUniqueBy(t *testing.T) { + assert := internal.NewAssert(t, "TestUniqueBy") + + actual := UniqueBy([]int{1, 2, 3, 4, 5, 6}, func(val int) int { + return val % 4 + }) + assert.Equal([]int{1, 2, 3, 0}, actual) +} + func TestUnion(t *testing.T) { assert := internal.NewAssert(t, "TestUnion")