From 28c53efaaa3958f42b1c3a0e31870e148051136b Mon Sep 17 00:00:00 2001 From: joshjennings98 Date: Wed, 15 Oct 2025 13:19:32 +0100 Subject: [PATCH 1/2] :sparkles: `collection` Add functions for converting maps to slices in a stable/ordered way --- changes/20251015131907.feature | 1 + utils/collection/parseLists.go | 19 +++++++++++++++++++ utils/collection/parseLists_test.go | 9 +++++++++ 3 files changed, 29 insertions(+) create mode 100644 changes/20251015131907.feature diff --git a/changes/20251015131907.feature b/changes/20251015131907.feature new file mode 100644 index 0000000000..a895160321 --- /dev/null +++ b/changes/20251015131907.feature @@ -0,0 +1 @@ +:sparkles: `collection` Add functions for converting maps to slices in a stable/ordered way diff --git a/utils/collection/parseLists.go b/utils/collection/parseLists.go index 9c3b47b959..2021560101 100644 --- a/utils/collection/parseLists.go +++ b/utils/collection/parseLists.go @@ -5,7 +5,9 @@ package collection import ( + "cmp" "fmt" + "maps" "slices" "strings" "unicode" @@ -170,3 +172,20 @@ func ConvertMapToCommaSeparatedList[K comparable, V any](pairs map[K]V) string { func ConvertMapToCommaSeparatedPairsList[K comparable, V any](pairs map[K]V, pairSeparator string) string { return ConvertSliceToCommaSeparatedList[string](ConvertMapToPairSlice[K, V](pairs, pairSeparator)) } + +// ConvertMapToSliceStable converts a map to a slice and ensures that the ordering will always be the same +func ConvertMapToSliceStable[K cmp.Ordered, V any](pairs map[K]V) []string { + if len(pairs) == 0 { + return nil + } + slice := make([]string, 0, len(pairs)*2) + for _, key := range slices.Sorted(maps.Keys(pairs)) { + slice = append(slice, fmt.Sprintf("%v", key), fmt.Sprintf("%v", pairs[key])) + } + return slice +} + +// ConvertMapToCommaSeparatedListStable converts a map to a commar-separated list and ensures that the ordering will always be the same +func ConvertMapToCommaSeparatedListStable[K cmp.Ordered, V any](pairs map[K]V) string { + return ConvertSliceToCommaSeparatedList[string](ConvertMapToSliceStable[K, V](pairs)) +} diff --git a/utils/collection/parseLists_test.go b/utils/collection/parseLists_test.go index 7e78d990de..039ecd9674 100644 --- a/utils/collection/parseLists_test.go +++ b/utils/collection/parseLists_test.go @@ -181,6 +181,7 @@ func TestParseCommaSeparatedPairListToMap(t *testing.T) { {"Normal 10", ",, ,, ,", map[string]string{}, nil, "+"}, {"Normal 11", ConvertMapToCommaSeparatedPairsList[string, string](randomMap, "/"), randomMap, nil, "/"}, {"Normal 12", ConvertMapToCommaSeparatedPairsList[string, string](randomMap, " "), randomMap, nil, " "}, + {"Normal 13", ConvertMapToCommaSeparatedListStable[string, string](randomMap), randomMap, nil, ","}, {"Bad 1", "one", nil, commonerrors.ErrInvalid, "+"}, {"Bad 1", "one, two, three", nil, commonerrors.ErrInvalid, "+"}, {"Bad 2", "one element with spaces", nil, commonerrors.ErrInvalid, "+"}, @@ -195,3 +196,11 @@ func TestParseCommaSeparatedPairListToMap(t *testing.T) { }) } } + +func TestConvertMapToCommaSeparatedListStable(t *testing.T) { + testMap := map[string]string{"hello": "world", "adrien": "cabarbaye", "fish": "cake", "apple": "pie"} + expected := "adrien,cabarbaye,apple,pie,fish,cake,hello,world" + for range 100 { + assert.Equal(t, expected, ConvertMapToCommaSeparatedListStable(testMap)) + } +} From 84b614b1e1aa0d51e76bcd786cd8c8cfc97efe6f Mon Sep 17 00:00:00 2001 From: joshjennings98 Date: Wed, 15 Oct 2025 14:28:55 +0100 Subject: [PATCH 2/2] rename --- utils/collection/parseLists.go | 10 +++++----- utils/collection/parseLists_test.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/collection/parseLists.go b/utils/collection/parseLists.go index 2021560101..24e74ed80c 100644 --- a/utils/collection/parseLists.go +++ b/utils/collection/parseLists.go @@ -173,8 +173,8 @@ func ConvertMapToCommaSeparatedPairsList[K comparable, V any](pairs map[K]V, pai return ConvertSliceToCommaSeparatedList[string](ConvertMapToPairSlice[K, V](pairs, pairSeparator)) } -// ConvertMapToSliceStable converts a map to a slice and ensures that the ordering will always be the same -func ConvertMapToSliceStable[K cmp.Ordered, V any](pairs map[K]V) []string { +// ConvertMapToOrderedSlice converts a map to a slice and ensures that the ordering will always be the same +func ConvertMapToOrderedSlice[K cmp.Ordered, V any](pairs map[K]V) []string { if len(pairs) == 0 { return nil } @@ -185,7 +185,7 @@ func ConvertMapToSliceStable[K cmp.Ordered, V any](pairs map[K]V) []string { return slice } -// ConvertMapToCommaSeparatedListStable converts a map to a commar-separated list and ensures that the ordering will always be the same -func ConvertMapToCommaSeparatedListStable[K cmp.Ordered, V any](pairs map[K]V) string { - return ConvertSliceToCommaSeparatedList[string](ConvertMapToSliceStable[K, V](pairs)) +// ConvertMapToOrderedCommaSeparatedList converts a map to a commar-separated list and ensures that the ordering will always be the same +func ConvertMapToOrderedCommaSeparatedList[K cmp.Ordered, V any](pairs map[K]V) string { + return ConvertSliceToCommaSeparatedList[string](ConvertMapToOrderedSlice[K, V](pairs)) } diff --git a/utils/collection/parseLists_test.go b/utils/collection/parseLists_test.go index 039ecd9674..17b3eee64a 100644 --- a/utils/collection/parseLists_test.go +++ b/utils/collection/parseLists_test.go @@ -181,7 +181,7 @@ func TestParseCommaSeparatedPairListToMap(t *testing.T) { {"Normal 10", ",, ,, ,", map[string]string{}, nil, "+"}, {"Normal 11", ConvertMapToCommaSeparatedPairsList[string, string](randomMap, "/"), randomMap, nil, "/"}, {"Normal 12", ConvertMapToCommaSeparatedPairsList[string, string](randomMap, " "), randomMap, nil, " "}, - {"Normal 13", ConvertMapToCommaSeparatedListStable[string, string](randomMap), randomMap, nil, ","}, + {"Normal 13", ConvertMapToOrderedCommaSeparatedList[string, string](randomMap), randomMap, nil, ","}, {"Bad 1", "one", nil, commonerrors.ErrInvalid, "+"}, {"Bad 1", "one, two, three", nil, commonerrors.ErrInvalid, "+"}, {"Bad 2", "one element with spaces", nil, commonerrors.ErrInvalid, "+"}, @@ -201,6 +201,6 @@ func TestConvertMapToCommaSeparatedListStable(t *testing.T) { testMap := map[string]string{"hello": "world", "adrien": "cabarbaye", "fish": "cake", "apple": "pie"} expected := "adrien,cabarbaye,apple,pie,fish,cake,hello,world" for range 100 { - assert.Equal(t, expected, ConvertMapToCommaSeparatedListStable(testMap)) + assert.Equal(t, expected, ConvertMapToOrderedCommaSeparatedList(testMap)) } }