diff --git a/functions/core/.gitkeep b/functions/core/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/functions/core/filter_slice.go b/functions/core/filter_slice.go new file mode 100644 index 00000000..41b1db50 --- /dev/null +++ b/functions/core/filter_slice.go @@ -0,0 +1,13 @@ +package core + +// FilterSlice returns a new slice containing only elements where pred returns true. +// Does not mutate the original slice. +func FilterSlice[T any](xs []T, pred func(T) bool) []T { + result := make([]T, 0, len(xs)) + for _, x := range xs { + if pred(x) { + result = append(result, x) + } + } + return result +} diff --git a/functions/core/filter_slice.md b/functions/core/filter_slice.md new file mode 100644 index 00000000..448873b0 --- /dev/null +++ b/functions/core/filter_slice.md @@ -0,0 +1,32 @@ +--- +name: filter_slice +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func FilterSlice[T any](xs []T, pred func(T) bool) []T" +description: "Filtra un slice aplicando un predicado sin mutar el original. Retorna un nuevo slice con los elementos que cumplen la condicion." +tags: [slice, functional, generic, filter] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: true +tests: ["filtra pares", "slice vacio retorna vacio", "ningun match retorna vacio"] +test_file_path: "functions/core/filter_slice_test.go" +file_path: "functions/core/filter_slice.go" +--- + +## Ejemplo + +```go +evens := FilterSlice([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 }) +// evens = [2, 4] +``` + +## Notas + +Funcion pura generica. Crea un nuevo slice con capacidad pre-alocada al tamaño del original para minimizar reallocs. diff --git a/functions/core/filter_slice_test.go b/functions/core/filter_slice_test.go new file mode 100644 index 00000000..1cceea00 --- /dev/null +++ b/functions/core/filter_slice_test.go @@ -0,0 +1,28 @@ +package core + +import ( + "testing" +) + +func TestFilterSlice(t *testing.T) { + t.Run("filtra pares", func(t *testing.T) { + got := FilterSlice([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 }) + if len(got) != 2 || got[0] != 2 || got[1] != 4 { + t.Errorf("got %v, want [2 4]", got) + } + }) + + t.Run("slice vacio retorna vacio", func(t *testing.T) { + got := FilterSlice([]int{}, func(n int) bool { return true }) + if len(got) != 0 { + t.Errorf("got %v, want []", got) + } + }) + + t.Run("ningun match retorna vacio", func(t *testing.T) { + got := FilterSlice([]int{1, 3, 5}, func(n int) bool { return n%2 == 0 }) + if len(got) != 0 { + t.Errorf("got %v, want []", got) + } + }) +} diff --git a/functions/core/map_slice.go b/functions/core/map_slice.go new file mode 100644 index 00000000..be2d32ef --- /dev/null +++ b/functions/core/map_slice.go @@ -0,0 +1,11 @@ +package core + +// MapSlice applies fn to each element of xs and returns a new slice with the results. +// Does not mutate the original slice. +func MapSlice[T any, U any](xs []T, fn func(T) U) []U { + result := make([]U, len(xs)) + for i, x := range xs { + result[i] = fn(x) + } + return result +} diff --git a/functions/core/map_slice.md b/functions/core/map_slice.md new file mode 100644 index 00000000..61904bb8 --- /dev/null +++ b/functions/core/map_slice.md @@ -0,0 +1,32 @@ +--- +name: map_slice +kind: function +lang: go +domain: core +version: "1.0.0" +purity: pure +signature: "func MapSlice[T any, U any](xs []T, fn func(T) U) []U" +description: "Transforma cada elemento de un slice aplicando una funcion. Retorna un nuevo slice del mismo tamaño con los resultados." +tags: [slice, functional, generic, map, transform] +uses_functions: [] +uses_types: [] +returns: [] +returns_optional: false +error_type: "" +imports: [] +tested: true +tests: ["transforma enteros a strings", "slice vacio retorna vacio", "preserva orden"] +test_file_path: "functions/core/map_slice_test.go" +file_path: "functions/core/map_slice.go" +--- + +## Ejemplo + +```go +strs := MapSlice([]int{1, 2, 3}, func(n int) string { return fmt.Sprintf("%d", n) }) +// strs = ["1", "2", "3"] +``` + +## Notas + +Funcion pura generica con dos type parameters: T (input) y U (output). Pre-aloca el slice resultado al tamaño exacto. diff --git a/functions/core/map_slice_test.go b/functions/core/map_slice_test.go new file mode 100644 index 00000000..f3e9cd15 --- /dev/null +++ b/functions/core/map_slice_test.go @@ -0,0 +1,29 @@ +package core + +import ( + "fmt" + "testing" +) + +func TestMapSlice(t *testing.T) { + t.Run("transforma enteros a strings", func(t *testing.T) { + got := MapSlice([]int{1, 2, 3}, func(n int) string { return fmt.Sprintf("%d", n) }) + if len(got) != 3 || got[0] != "1" || got[1] != "2" || got[2] != "3" { + t.Errorf("got %v", got) + } + }) + + t.Run("slice vacio retorna vacio", func(t *testing.T) { + got := MapSlice([]int{}, func(n int) int { return n * 2 }) + if len(got) != 0 { + t.Errorf("got %v, want []", got) + } + }) + + t.Run("preserva orden", func(t *testing.T) { + got := MapSlice([]int{3, 1, 2}, func(n int) int { return n * 10 }) + if got[0] != 30 || got[1] != 10 || got[2] != 20 { + t.Errorf("got %v, want [30 10 20]", got) + } + }) +}