From 30c9b86d62ffa180679c866bd1ac2e554eb55e2b Mon Sep 17 00:00:00 2001 From: Ononiwu Maureen <59079323+Chinwendu20@users.noreply.github.com> Date: Sun, 5 May 2024 21:05:59 +0100 Subject: [PATCH] fn: Added new slice functions. Signed-off-by: Ononiwu Maureen <59079323+Chinwendu20@users.noreply.github.com> --- fn/slice.go | 30 ++++++++++++++ fn/slice_test.go | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/fn/slice.go b/fn/slice.go index fe821bff7..2e27acc45 100644 --- a/fn/slice.go +++ b/fn/slice.go @@ -1,5 +1,13 @@ package fn +import "golang.org/x/exp/constraints" + +// Number is a type constraint for all numeric types in Go (integers, +// float and complex numbers) +type Number interface { + constraints.Integer | constraints.Float | constraints.Complex +} + // All returns true when the supplied predicate evaluates to true for all of // the values in the slice. func All[A any](pred func(A) bool, s []A) bool { @@ -168,3 +176,25 @@ func ZipWith[A, B, C any](f func(A, B) C, a []A, b []B) []C { return res } + +// SliceToMap converts a slice to a map using the provided key and value +// functions. +func SliceToMap[A any, K comparable, V any](s []A, keyFunc func(A) K, + valueFunc func(A) V) map[K]V { + + res := make(map[K]V, len(s)) + for _, val := range s { + key := keyFunc(val) + value := valueFunc(val) + res[key] = value + } + + return res +} + +// Sum calculates the sum of a slice of numbers, `items`. +func Sum[B Number](items []B) B { + return Foldl(func(a, b B) B { + return a + b + }, 0, items) +} diff --git a/fn/slice_test.go b/fn/slice_test.go index 0178cc946..de02be836 100644 --- a/fn/slice_test.go +++ b/fn/slice_test.go @@ -1,6 +1,7 @@ package fn import ( + "fmt" "slices" "testing" @@ -136,3 +137,107 @@ func TestZipWith(t *testing.T) { z, []bool{false, true, false, false, false}, )) } + +// TestSum checks if the Sum function correctly calculates the sum of the +// numbers in the slice. +func TestSum(t *testing.T) { + tests := []struct { + name string + items interface{} + result interface{} + }{ + { + name: "Sum of positive integers", + items: []int{1, 2, 3}, + result: 6, + }, + { + name: "Sum of negative integers", + items: []int{-1, -2, -3}, + result: -6, + }, + { + name: "Sum of float numbers", + items: []float64{1.1, 2.2, 3.3}, + result: 6.6, + }, + { + name: "Sum of complex numbers", + items: []complex128{ + complex(1, 1), + complex(2, 2), + complex(3, 3), + }, + result: complex(6, 6), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + switch v := tt.items.(type) { + case []int: + require.Equal(t, tt.result, Sum(v)) + case []float64: + require.Equal(t, tt.result, Sum(v)) + case []complex128: + require.Equal(t, tt.result, Sum(v)) + } + }) + } +} + +// TestSliceToMap tests the SliceToMap function. +func TestSliceToMap(t *testing.T) { + tests := []struct { + name string + slice []int + keyFunc func(int) int + valueFunc func(int) string + expected map[int]string + }{ + { + name: "Integers to string map", + slice: []int{1, 2, 3}, + keyFunc: func(a int) int { return a }, + valueFunc: func(a int) string { + return fmt.Sprintf("Value%d", a) + }, + expected: map[int]string{ + 1: "Value1", + 2: "Value2", + 3: "Value3", + }, + }, + { + name: "Duplicates in slice", + slice: []int{1, 2, 2, 3}, + keyFunc: func(a int) int { return a }, + valueFunc: func(a int) string { + return fmt.Sprintf("Value%d", a) + }, + expected: map[int]string{ + 1: "Value1", + 2: "Value2", + 3: "Value3", + }, + }, + { + name: "Empty slice", + slice: []int{}, + keyFunc: func(a int) int { return a }, + valueFunc: func(a int) string { + return fmt.Sprintf("Value%d", a) + }, + expected: map[int]string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal( + t, tt.expected, + SliceToMap(tt.slice, tt.keyFunc, tt.valueFunc), + ) + }) + } +}