From 0e73f4a2f5d5d5ad70d7dd118dcd9499a4d50707 Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Tue, 22 Jul 2025 11:26:24 +0200 Subject: [PATCH 1/2] add ProjectSliceToMap function --- pkg/collections/utils.go | 29 ++++++++++++++++++++++++++- pkg/collections/utils_test.go | 37 ++++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/pkg/collections/utils.go b/pkg/collections/utils.go index 3c2c1dc..0690c49 100644 --- a/pkg/collections/utils.go +++ b/pkg/collections/utils.go @@ -1,10 +1,20 @@ package collections -// ProjectSlice takes a slice and a projection function and applies this function to each element of the slice. +// ProjectSliceToSlice takes a slice and a projection function and applies this function to each element of the slice. // It returns a new slice containing the results of the projection. // The original slice is not modified. // If the projection function is nil, it returns nil. +// +// Deprecated: With the introduction of ProjectSliceToMap, this function has been replaced by ProjectSliceToSlice for better naming consistency. func ProjectSlice[X any, Y any](src []X, project func(X) Y) []Y { + return ProjectSliceToSlice(src, project) +} + +// ProjectSliceToSlice takes a slice and a projection function and applies this function to each element of the slice. +// It returns a new slice containing the results of the projection. +// The original slice is not modified. +// If the projection function is nil, it returns nil. +func ProjectSliceToSlice[X any, Y any](src []X, project func(X) Y) []Y { if project == nil { return nil } @@ -15,6 +25,23 @@ func ProjectSlice[X any, Y any](src []X, project func(X) Y) []Y { return res } +// ProjectSliceToMap takes a slice and a projection function and applies this function to each element of the slice. +// It returns a new map containing the results of the projection. +// The original slice is not modified. +// Note that the resulting map may be smaller if the projection function does not guarantee unique keys. +// If the projection function is nil, it returns nil. +func ProjectSliceToMap[X any, K comparable, V any](src []X, project func(X) (K, V)) map[K]V { + if project == nil { + return nil + } + res := make(map[K]V, len(src)) + for _, x := range src { + k, v := project(x) + res[k] = v + } + return res +} + // ProjectMapToSlice takes a map and a projection function and applies this function to each key-value pair in the map. // It returns a new slice containing the results of the projection. // The original map is not modified. diff --git a/pkg/collections/utils_test.go b/pkg/collections/utils_test.go index 9d2e61d..f796409 100644 --- a/pkg/collections/utils_test.go +++ b/pkg/collections/utils_test.go @@ -12,7 +12,7 @@ import ( var _ = Describe("Utils Tests", func() { - Context("ProjectSlice", func() { + Context("ProjectSliceToSlice", func() { projectFunc := func(i int) int { return i * 2 @@ -20,19 +20,46 @@ var _ = Describe("Utils Tests", func() { It("should use the projection function on each element of the slice", func() { src := []int{1, 2, 3, 4} - projected := collections.ProjectSlice(src, projectFunc) + projected := collections.ProjectSliceToSlice(src, projectFunc) Expect(projected).To(Equal([]int{2, 4, 6, 8})) Expect(src).To(Equal([]int{1, 2, 3, 4}), "original slice should not be modified") }) It("should return an empty slice for an empty or nil input slice", func() { - Expect(collections.ProjectSlice(nil, projectFunc)).To(BeEmpty()) - Expect(collections.ProjectSlice([]int{}, projectFunc)).To(BeEmpty()) + Expect(collections.ProjectSliceToSlice(nil, projectFunc)).To(BeEmpty()) + Expect(collections.ProjectSliceToSlice([]int{}, projectFunc)).To(BeEmpty()) }) It("should return nil for a nil projection function", func() { src := []int{1, 2, 3, 4} - projected := collections.ProjectSlice[int, int](src, nil) + projected := collections.ProjectSliceToSlice[int, int](src, nil) + Expect(projected).To(BeNil()) + Expect(src).To(Equal([]int{1, 2, 3, 4}), "original slice should not be modified") + }) + + }) + + Context("ProjectSliceToMap", func() { + + projectFunc := func(i int) (int, int) { + return i, i * 2 + } + + It("should use the projection function on each element of the slice", func() { + src := []int{1, 2, 3, 4} + projected := collections.ProjectSliceToMap(src, projectFunc) + Expect(projected).To(Equal(map[int]int{1: 2, 2: 4, 3: 6, 4: 8})) + Expect(src).To(Equal([]int{1, 2, 3, 4}), "original slice should not be modified") + }) + + It("should return an empty slice for an empty or nil input slice", func() { + Expect(collections.ProjectSliceToMap(nil, projectFunc)).To(BeEmpty()) + Expect(collections.ProjectSliceToMap([]int{}, projectFunc)).To(BeEmpty()) + }) + + It("should return nil for a nil projection function", func() { + src := []int{1, 2, 3, 4} + projected := collections.ProjectSliceToMap[int, int, int](src, nil) Expect(projected).To(BeNil()) Expect(src).To(Equal([]int{1, 2, 3, 4}), "original slice should not be modified") }) From caa423a345caa3b34b25146b0dcc53357c62c53e Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Tue, 5 Aug 2025 13:10:29 +0200 Subject: [PATCH 2/2] fix rebasing conflicts --- pkg/conditions/updater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/conditions/updater.go b/pkg/conditions/updater.go index fc47495..dffe6d3 100644 --- a/pkg/conditions/updater.go +++ b/pkg/conditions/updater.go @@ -133,7 +133,7 @@ func (c *conditionUpdater) RemoveCondition(conType string) *conditionUpdater { // The conditions are returned sorted by their type. // The second return value indicates whether the condition list has actually changed. func (c *conditionUpdater) Conditions() ([]metav1.Condition, bool) { - res := collections.ProjectSlice(c.updatedConditions(), func(con metav1.Condition) metav1.Condition { + res := collections.ProjectSliceToSlice(c.updatedConditions(), func(con metav1.Condition) metav1.Condition { if c.original[con.Type].Status == con.Status { // if the status has not changed, reset the LastTransitionTime to the original value con.LastTransitionTime = c.original[con.Type].LastTransitionTime