From a7f49c07192375823c129591b3a9a3349682a599 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Santin Date: Wed, 10 May 2023 18:51:06 -0300 Subject: [PATCH] Add conversion of slices to map grouping by field Add the method ToMapGroupedBy that receives a slice and a function to extract a key from each slice item. As result it returns a map grouping all items having the same key. --- slices/slice.go | 11 +++++++++++ slices/slice_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/slices/slice.go b/slices/slice.go index 9139241..7a58391 100644 --- a/slices/slice.go +++ b/slices/slice.go @@ -577,6 +577,17 @@ func ToMap[S ~[]V, V any](items S) map[int]V { return result } +// ToMapGroupedBy converts the given slice into a map where keys are values returned +// from keyExtractor function and values are items from the given slice +func ToMapGroupedBy[V any, T comparable](items []V, keyExtractor func(V) T) map[T][]V { + result := make(map[T][]V) + for _, item := range items { + key := keyExtractor(item) + result[key] = append(result[key], item) + } + return result +} + // ToKeys converts the given slice into a map where items from the slice are the keys // of the resulting map and all values are equal to the given `val` value. func ToKeys[S ~[]K, K comparable, V any](items S, val V) map[K]V { diff --git a/slices/slice_test.go b/slices/slice_test.go index 7ac1f95..3328aab 100644 --- a/slices/slice_test.go +++ b/slices/slice_test.go @@ -532,3 +532,32 @@ func TestWithout(t *testing.T) { f([]int{1, 1, 2, 3, 1, 4, 1}, []int{1}, []int{2, 3, 4}) } + +func TestToMapGroupedBy(t *testing.T) { + is := is.New(t) + + type employee struct { + Name string + Department string + } + + f := func(given []employee, expected map[string][]employee) { + actual := slices.ToMapGroupedBy(given, func(emp employee) string { + return emp.Department + }) + is.Equal(expected, actual) + } + + employeeJohn := employee{Name: "John", Department: "Engineering"} + employeeEva := employee{Name: "Eva", Department: "HR"} + employeeCarlos := employee{Name: "Carlos", Department: "Engineering"} + + f([]employee{employeeJohn, employeeEva, employeeCarlos}, map[string][]employee{ + "Engineering": {employeeJohn, employeeCarlos}, + "HR": {employeeEva}, + }) + + f([]employee{}, map[string][]employee{}) + + f(nil, map[string][]employee{}) +}