diff --git a/README.md b/README.md index 39bcba5f..3de8240c 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,8 @@ Supported helpers for slices: - [Repeat](#repeat) - [RepeatBy](#repeatby) - [KeyBy](#keyby) -- [Associate / SliceToMap](#associate-alias-slicetomap) +- [SliceToMap / Associate](#slicetomap-alias-associate) +- [FilterSliceToMap](#filterslicetomap) - [Keyify](#keyify) - [Drop](#drop) - [DropRight](#dropright) @@ -299,6 +300,9 @@ Concurrency helpers: - [Debounce](#debounce) - [DebounceBy](#debounceby) - [Throttle](#throttle) +- [ThrottleWithCount](#throttle) +- [ThrottleBy](#throttle) +- [ThrottleByWithCount](#throttle) - [Synchronize](#synchronize) - [Async](#async) - [Transaction](#transaction) @@ -756,7 +760,7 @@ result := lo.KeyBy(characters, func(char Character) string { [[play](https://go.dev/play/p/mdaClUAT-zZ)] -### Associate (alias: SliceToMap) +### SliceToMap (alias: Associate) Returns a map containing key-value pairs provided by transform function applied to elements of the given slice. If any of two pairs would have the same key the last one gets added to the map. @@ -766,7 +770,7 @@ The order of keys in returned map is not specified and is not guaranteed to be t ```go in := []*foo{{baz: "apple", bar: 1}, {baz: "banana", bar: 2}} -aMap := lo.Associate(in, func (f *foo) (string, int) { +aMap := lo.SliceToMap(in, func (f *foo) (string, int) { return f.baz, f.bar }) // map[string][int]{ "apple":1, "banana":2 } @@ -774,6 +778,26 @@ aMap := lo.Associate(in, func (f *foo) (string, int) { [[play](https://go.dev/play/p/WHa2CfMO3Lr)] +### FilterSliceToMap + +Returns a map containing key-value pairs provided by transform function applied to elements of the given slice. + +If any of two pairs would have the same key the last one gets added to the map. + +The order of keys in returned map is not specified and is not guaranteed to be the same from the original array. + +The third return value of the transform function is a boolean that indicates whether the key-value pair should be included in the map. + + +```go +list := []string{"a", "aa", "aaa"} + +result := lo.FilterSliceToMap(list, func(str string) (string, int, bool) { + return str, len(str), len(str) > 1 +}) +// map[string][int]{"aa":2 "aaa":3} +``` + ### Keyify Returns a map with each unique element of the slice as a key. diff --git a/slice.go b/slice.go index dd0c458a..e03cba04 100644 --- a/slice.go +++ b/slice.go @@ -387,6 +387,23 @@ func SliceToMap[T any, K comparable, V any](collection []T, transform func(item return Associate(collection, transform) } +// FilterSliceToMap returns a map containing key-value pairs provided by transform function applied to elements of the given slice. +// If any of two pairs would have the same key the last one gets added to the map. +// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array. +// The third return value of the transform function is a boolean that indicates whether the key-value pair should be included in the map. +func FilterSliceToMap[T any, K comparable, V any](collection []T, transform func(item T) (K, V, bool)) map[K]V { + result := make(map[K]V, len(collection)) + + for i := range collection { + k, v, ok := transform(collection[i]) + if ok { + result[k] = v + } + } + + return result +} + // Keyify returns a map with each unique element of the slice as a key. func Keyify[T comparable, Slice ~[]T](collection Slice) map[T]struct{} { result := make(map[T]struct{}, len(collection)) diff --git a/slice_example_test.go b/slice_example_test.go index 241dbfdf..ba639d33 100644 --- a/slice_example_test.go +++ b/slice_example_test.go @@ -276,10 +276,10 @@ func ExampleKeyBy() { // Output: map[1:a 2:aa 3:aaa] } -func ExampleAssociate() { +func ExampleSliceToMap() { list := []string{"a", "aa", "aaa"} - result := Associate(list, func(str string) (string, int) { + result := SliceToMap(list, func(str string) (string, int) { return str, len(str) }) @@ -287,6 +287,17 @@ func ExampleAssociate() { // Output: map[a:1 aa:2 aaa:3] } +func ExampleFilterSliceToMap() { + list := []string{"a", "aa", "aaa"} + + result := FilterSliceToMap(list, func(str string) (string, int, bool) { + return str, len(str), len(str) > 1 + }) + + fmt.Printf("%v", result) + // Output: map[aa:2 aaa:3] +} + func ExampleKeyify() { list := []string{"a", "a", "b", "b", "d"} diff --git a/slice_test.go b/slice_test.go index 1be4bded..956832d8 100644 --- a/slice_test.go +++ b/slice_test.go @@ -531,6 +531,41 @@ func TestSliceToMap(t *testing.T) { } } +func TestFilterSliceToMap(t *testing.T) { + t.Parallel() + + type foo struct { + baz string + bar int + } + transform := func(f *foo) (string, int, bool) { + return f.baz, f.bar, f.bar > 1 + } + testCases := []struct { + in []*foo + expect map[string]int + }{ + { + in: []*foo{{baz: "apple", bar: 1}}, + expect: map[string]int{}, + }, + { + in: []*foo{{baz: "apple", bar: 1}, {baz: "banana", bar: 2}}, + expect: map[string]int{"banana": 2}, + }, + { + in: []*foo{{baz: "apple", bar: 1}, {baz: "apple", bar: 2}}, + expect: map[string]int{"apple": 2}, + }, + } + for i, testCase := range testCases { + t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { + is := assert.New(t) + is.Equal(FilterSliceToMap(testCase.in, transform), testCase.expect) + }) + } +} + func TestKeyify(t *testing.T) { t.Parallel() is := assert.New(t)