From ba8bbb219a578f8c2ba717784d4b5a57e6e192ce Mon Sep 17 00:00:00 2001 From: Chris Pappas Date: Tue, 23 Aug 2022 09:16:02 -0500 Subject: [PATCH 1/3] Add maps.ToKeys method - also suppress gosec warnings for rand.Int() calls --- maps/maps.go | 8 ++++++++ maps/maps_test.go | 29 +++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/maps/maps.go b/maps/maps.go index ad112e7..bed1dc1 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -18,3 +18,11 @@ func ToSlice[M ~map[K]V, K comparable, V, R any](items M, f func(K, V) R) []R { } return out } + +func ToKeys[In any, Key comparable](arr map[Key]In) []Key { + out := make([]Key, 0, len(arr)) + for key := range arr { + out = append(out, key) + } + return out +} diff --git a/maps/maps_test.go b/maps/maps_test.go index 8fcd495..f73699c 100644 --- a/maps/maps_test.go +++ b/maps/maps_test.go @@ -13,6 +13,31 @@ const benchmarkArrayLength = 10_000 var benchResult []int +func TestToKeys(t *testing.T) { + t.Run( + "String Keys", func(t *testing.T) { + test := map[string]int{ + "one": 1, + "two": 2, + "three": 3, + } + keys := ToKeys(test) + require.ElementsMatch(t, []string{"one", "two", "three"}, keys) + }, + ) + t.Run( + "Int Keys", func(t *testing.T) { + test := map[int]string{ + 1: "one", + 2: "two", + 3: "three", + } + keys := ToKeys(test) + require.ElementsMatch(t, []int{1, 2, 3}, keys) + }, + ) +} + func TestToValues(t *testing.T) { nums := map[string]int{ "one": 1, @@ -44,7 +69,7 @@ func TestToSlice(t *testing.T) { func BenchmarkToValues(b *testing.B) { arr := make(map[int]int, benchmarkArrayLength) for i := range arr { - arr[i] = rand.Int() + arr[i] = rand.Int() //nolint:gosec } var r []int @@ -57,7 +82,7 @@ func BenchmarkToValues(b *testing.B) { func BenchmarkToSlice(b *testing.B) { arr := make(map[int]int, benchmarkArrayLength) for i := range arr { - arr[i] = rand.Int() + arr[i] = rand.Int() //nolint:gosec } var r []int for i := 0; i < b.N; i++ { From f735e36a83e567dbabc0da43e1465ab6bf8e6773 Mon Sep 17 00:00:00 2001 From: Chris Pappas Date: Tue, 23 Aug 2022 09:26:50 -0500 Subject: [PATCH 2/3] Make it even more efficient without using append - since we already know the size, we can just pre-allocate and directly access the index --- maps/maps.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/maps/maps.go b/maps/maps.go index bed1dc1..80f3a6e 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -2,9 +2,11 @@ package maps // ToValues returns an array of just the values of the input Map. func ToValues[In any, Key comparable](arr map[Key]In) []In { - out := make([]In, 0, len(arr)) - for _, elem := range arr { - out = append(out, elem) + i := 0 + out := make([]In, len(arr)) + for _, value := range arr { + out[i] = value + i++ } return out } @@ -12,17 +14,21 @@ func ToValues[In any, Key comparable](arr map[Key]In) []In { // ToSlice applies the function to each element of the input map, and returns an // array of the results. func ToSlice[M ~map[K]V, K comparable, V, R any](items M, f func(K, V) R) []R { - out := make([]R, 0, len(items)) + i := 0 + out := make([]R, len(items)) for k, v := range items { - out = append(out, f(k, v)) + out[i] = f(k, v) + i++ } return out } func ToKeys[In any, Key comparable](arr map[Key]In) []Key { - out := make([]Key, 0, len(arr)) + i := 0 + out := make([]Key, len(arr)) for key := range arr { - out = append(out, key) + out[i] = key + i++ } return out } From f07a92e130ed940391ddfc0064ebce8e4eb8b451 Mon Sep 17 00:00:00 2001 From: Chris Pappas Date: Thu, 1 Sep 2022 09:23:10 -0500 Subject: [PATCH 3/3] Add missing docs and example test --- maps/maps.go | 1 + maps/maps_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/maps/maps.go b/maps/maps.go index 80f3a6e..2d01703 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -23,6 +23,7 @@ func ToSlice[M ~map[K]V, K comparable, V, R any](items M, f func(K, V) R) []R { return out } +// ToKeys returns an array of the keys of the input Map. func ToKeys[In any, Key comparable](arr map[Key]In) []Key { i := 0 out := make([]Key, len(arr)) diff --git a/maps/maps_test.go b/maps/maps_test.go index f73699c..df2a94c 100644 --- a/maps/maps_test.go +++ b/maps/maps_test.go @@ -119,3 +119,16 @@ func ExampleToSlice() { fmt.Println(results) // Output: [1 in text is one 2 in text is two 3 in text is three] } + +func ExampleToKeys() { + nums := map[string]int{ + "a": 1, + "b": 2, + "c": 3, + } + results := ToKeys(nums) + + sort.Strings(results) // order is not guaranteed for map keys + fmt.Println(results) + // Output: [a b c] +}