From ad68d7d4fd80068121a5fa61b2756258417360ed Mon Sep 17 00:00:00 2001 From: nicklausliu Date: Thu, 29 Aug 2024 10:45:15 +0800 Subject: [PATCH] feat: add UniqMap --- README.md | 18 ++++++++++++++++++ slice.go | 15 +++++++++++++++ slice_example_test.go | 15 +++++++++++++++ slice_test.go | 17 +++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/README.md b/README.md index ff91a992..ac04d33b 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Supported helpers for slices: - [Filter](#filter) - [Map](#map) +- [UniqMap](#uniqmap) - [FilterMap](#filtermap) - [FlatMap](#flatmap) - [Reduce](#reduce) @@ -341,6 +342,23 @@ lop.Map([]int64{1, 2, 3, 4}, func(x int64, _ int) string { // []string{"1", "2", "3", "4"} ``` +### UniqMap + +UniqMap manipulates a slice and transforms it to a slice of another type with unique values. + +```go +type User struct { + Name string + Age int +} +users := []User{{Name: "Alex", Age: 10}, {Name: "Alex", Age: 12}, {Name: "Bob", Age: 11}, {Name: "Alice", Age: 20}} + +names := UniqMap(users, func(u User, index int) string { + return u.Name +}) +// []string{"Alex", "Bob", "Alice"} +``` + ### FilterMap Returns a slice which obtained after both filtering and mapping using the given callback function. diff --git a/slice.go b/slice.go index d2d3fd84..7e6226a6 100644 --- a/slice.go +++ b/slice.go @@ -33,6 +33,21 @@ func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R { return result } +// UniqMap manipulates a slice and transforms it to a slice of another type with unique values. +func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index int) R) []R { + result := make([]R, 0, len(collection)) + seen := make(map[R]struct{}, len(collection)) + + for i, item := range collection { + r := iteratee(item, i) + if _, ok := seen[r]; !ok { + result = append(result, r) + seen[r] = struct{}{} + } + } + return result +} + // FilterMap returns a slice which obtained after both filtering and mapping using the given callback function. // The callback function should return two values: // - the result of the mapping operation and diff --git a/slice_example_test.go b/slice_example_test.go index 0d64d8f0..5822364c 100644 --- a/slice_example_test.go +++ b/slice_example_test.go @@ -28,6 +28,21 @@ func ExampleMap() { // Output: [2 4 6 8] } +func ExampleUniqMap() { + type User struct { + Name string + Age int + } + users := []User{{Name: "Alex", Age: 10}, {Name: "Alex", Age: 12}, {Name: "Bob", Age: 11}, {Name: "Alice", Age: 20}} + + result := UniqMap(users, func(u User, index int) string { + return u.Name + }) + + fmt.Printf("%v", result) + // Output: [Alex Bob Alice] +} + func ExampleFilterMap() { list := []int64{1, 2, 3, 4} diff --git a/slice_test.go b/slice_test.go index abb9450e..8020c5cf 100644 --- a/slice_test.go +++ b/slice_test.go @@ -50,6 +50,23 @@ func TestMap(t *testing.T) { is.Equal(result2, []string{"1", "2", "3", "4"}) } +func TestUniqMap(t *testing.T) { + t.Parallel() + is := assert.New(t) + + type User struct { + Name string + age int + } + + users := []User{{Name: "Alice", age: 20}, {Name: "Alex", age: 21}, {Name: "Alex", age: 22}} + result := UniqMap(users, func(item User, index int) string { + return item.Name + }) + + is.Equal(result, []string{"Alice", "Alex"}) +} + func TestFilterMap(t *testing.T) { t.Parallel() is := assert.New(t)