Skip to content

Commit 3e740ba

Browse files
committed
feat(uniqby): adding _.uniqBy() style function
1 parent 98b583c commit 3e740ba

File tree

3 files changed

+96
-0
lines changed

3 files changed

+96
-0
lines changed

README.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,29 @@ see also, typesafe implementations: UniqInt_, UniqInt64_, UniqFloat32_, UniqFloa
654654
.. _UniqInt64: https://godoc.org/github.com/thoas/go-funk#UniqInt64
655655
.. _UniqString: https://godoc.org/github.com/thoas/go-funk#UniqString
656656

657+
funk.UniqBy
658+
.........
659+
660+
Creates an array with unique values returned by a callback.
661+
662+
.. code-block:: go
663+
664+
funk.UniqBy([]int{0, 1, 1, 2, 3, 0, 0, 12}, func(nbr int) int {
665+
return nbr % 3
666+
}) // []int{0, 1, 2}
667+
668+
foo1 := Foo{
669+
ID: 42,
670+
FirstName: "Bob",
671+
}
672+
foo2 := Foo{
673+
ID: 42,
674+
FirstName: "Bob",
675+
}
676+
funk.UniqBy([]Foo{foo1, foo2}, func(f Foo) int {
677+
return f.ID
678+
}) // []Foo{ Foo{ID: 42, Firstname: "Bob"} }
679+
657680
funk.Drop
658681
.........
659682

transform.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,44 @@ func Uniq(in interface{}) interface{} {
412412
panic(fmt.Sprintf("Type %s is not supported by Uniq", valueType.String()))
413413
}
414414

415+
// Uniq creates an array with unique values.
416+
func UniqBy(in interface{}, mapFunc interface{}) interface{} {
417+
if !IsFunction(mapFunc) {
418+
panic("Second argument must be function")
419+
}
420+
421+
value := reflect.ValueOf(in)
422+
valueType := value.Type()
423+
424+
kind := value.Kind()
425+
426+
funcValue := reflect.ValueOf(mapFunc)
427+
428+
if kind == reflect.Array || kind == reflect.Slice {
429+
length := value.Len()
430+
431+
result := makeSlice(value, 0)
432+
433+
seen := make(map[interface{}]bool, length)
434+
435+
for i := 0; i < length; i++ {
436+
val := value.Index(i)
437+
v := funcValue.Call([]reflect.Value{val})[0].Interface()
438+
439+
if _, ok := seen[v]; ok {
440+
continue
441+
}
442+
443+
seen[v] = true
444+
result = reflect.Append(result, val)
445+
}
446+
447+
return result.Interface()
448+
}
449+
450+
panic(fmt.Sprintf("Type %s is not supported by Uniq", valueType.String()))
451+
}
452+
415453
// ConvertSlice converts a slice type to another,
416454
// a perfect example would be to convert a slice of struct to a slice of interface.
417455
func ConvertSlice(in interface{}, out interface{}) {

transform_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,41 @@ func TestUniq(t *testing.T) {
256256
is.Equal(results, []string{"foo", "bar"})
257257
}
258258

259+
func TestUniqBy(t *testing.T) {
260+
is := assert.New(t)
261+
262+
results := UniqBy([]int{0, 1, 1, 2, 3, 0, 0, 12}, func(nbr int) int {
263+
return nbr % 3
264+
})
265+
fmt.Println(results)
266+
is.Len(results, 3)
267+
is.Equal(results, []int{0, 1, 2})
268+
269+
type foobar struct {
270+
foo string
271+
bar string
272+
}
273+
274+
foobar1 := foobar{
275+
foo: "foo",
276+
bar: "bar",
277+
}
278+
foobar2 := foobar{
279+
foo: "foo",
280+
bar: "baz",
281+
}
282+
foobar3 := foobar{
283+
foo: "foo",
284+
bar: "bar",
285+
}
286+
287+
results = UniqBy([]foobar{foobar1, foobar2, foobar3}, func(f foobar) string {
288+
return f.foo + f.bar
289+
})
290+
is.Len(results, 2)
291+
is.Equal(results, []foobar{foobar1, foobar2})
292+
}
293+
259294
func TestConvertSlice(t *testing.T) {
260295
instances := []*Foo{foo, foo2}
261296

0 commit comments

Comments
 (0)