Skip to content

Commit

Permalink
feat: adding FilterSliceToMap (#581)
Browse files Browse the repository at this point in the history
  • Loading branch information
samber authored Jan 26, 2025
1 parent 19d8355 commit 124d300
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 5 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -299,6 +300,9 @@ Concurrency helpers:
- [Debounce](#debounce)
- [DebounceBy](#debounceby)
- [Throttle](#throttle)
- [ThrottleWithCount](#throttle)
- [ThrottleBy](#throttle)
- [ThrottleByWithCount](#throttle)
- [Synchronize](#synchronize)
- [Async](#async)
- [Transaction](#transaction)
Expand Down Expand Up @@ -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.
Expand All @@ -766,14 +770,34 @@ 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 }
```

[[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.
Expand Down
17 changes: 17 additions & 0 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
15 changes: 13 additions & 2 deletions slice_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,17 +276,28 @@ 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)
})

fmt.Printf("%v", result)
// 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"}

Expand Down
35 changes: 35 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 124d300

Please sign in to comment.