Solidify fn map/filter/reduce/each package with array

pull/53/head
rwxrob 2 years ago
parent 6cd4df1060
commit d1cb39cdac
No known key found for this signature in database
GPG Key ID: 2B9111F33082AE77

@ -1,11 +1,41 @@
// Copyright 2022 Robert S. Muhlestein.
// SPDX-License-Identifier: Apache-2.0
/*
Package fn implements the traditional map/filter/reduce/each functions
and an array type (A) for those who prefer a more object-oriented
approach. Unlike other implementations, the array (slice) is always
first preventing the first-class in-line anonymous function from
obfuscating the parameter list of the functional function.
*/
package fn
// Map executes an operator function provided on each item in the
// slice returning a new slice. If error handling is needed it should be
// handled within an enclosure within the function. This keeps
import "github.com/rwxrob/bonzai/each"
// A is the equivalent of an array primitive in other functional
// languages. It is a generic slice of anything.
type A[T any] []T
func (a A[any]) Each(f func(i any)) { each.Do(a, f) }
func (a A[any]) E(f func(i any)) { each.Do(a, f) }
func (a A[any]) Map(f func(i any) any) A[any] { return Map(a, f) }
func (a A[any]) M(f func(i any) any) A[any] { return Map(a, f) }
func (a A[any]) Filter(f func(i any) bool) A[any] { return Filter(a, f) }
func (a A[any]) F(f func(i any) bool) A[any] { return Filter(a, f) }
func (a A[any]) Reduce(f func(i any, r *any)) *any { return Reduce(a, f) }
func (a A[any]) R(f func(i any, r *any)) *any { return Reduce(a, f) }
func (a A[any]) Print() { each.Print(a) }
func (a A[any]) Println() { each.Println(a) }
func (a A[any]) P() { each.Println(a) }
func (a A[any]) Printf(t string) { each.Printf(a, t) }
func (a A[any]) Log() { each.Log(a) }
func (a A[any]) Logf(f string) { each.Logf(a, f) }
// Map executes an operator function provided on each item in the slice
// returning a new slice with items of a potentially different type
// completely (which is different from using the Array.Map method which
// requires returning the same type). If error handling is needed it
// should be handled within an enclosure within the function. This keeps
// signatures simple and functional.
func Map[I any, O any](slice []I, f func(in I) O) []O {
list := []O{}
@ -14,3 +44,27 @@ func Map[I any, O any](slice []I, f func(in I) O) []O {
}
return list
}
// Filter applies the boolean function on each item only returning those
// items that evaluate to true.
func Filter[T any](slice []T, f func(in T) bool) []T {
list := []T{}
for _, i := range slice {
if f(i) {
list = append(list, i)
}
}
return list
}
// Reduce calls the given reducer function for every item in the slice
// passing a required reference to an item to hold the results If error
// handling is needed it should be handled within an enclosure within
// the function. This keeps signatures simple and functional.
func Reduce[T any, R any](slice []T, f func(in T, ref *R)) *R {
r := new(R)
for _, i := range slice {
f(i, r)
}
return r
}

@ -5,61 +5,79 @@ package fn_test
import (
"fmt"
"log"
"os"
"github.com/rwxrob/bonzai/fn"
)
func ExampleHasPrefix() {
set := []string{
"one", "two", "three", "four", "five", "six", "seven",
}
fmt.Println(fn.HasPrefix(set, "t"))
func ExampleA_a_is_for_array() {
fn.A[int]{1, 2, 3}.Print()
fmt.Println()
fn.A[string]{"one", "two", "three"}.Println()
// Output:
// [two three]
// 123
// one
// two
// three
}
func ExamplePrintln() {
set := []string{"doe", "ray", "mi"}
filter.Println(set)
bools := []bool{false, true, true}
filter.Println(bools)
func ExampleA_Each() {
fn.A[int]{1, 2, 3}.Each(func(i int) { fmt.Print(i) })
fn.A[int]{1, 2, 3}.E(func(i int) { fmt.Print(i) })
// Output:
// doe
// ray
// mi
// false
// true
// true
// 123123
}
func ExampleKeys() {
m1 := map[string]int{"two": 2, "three": 3, "one": 1}
m2 := map[string]string{"two": "two", "three": "three", "one": "one"}
fmt.Println(filter.Keys(m1))
fmt.Println(filter.Keys(m2))
func ExampleA_Map() {
AddOne := func(i int) int { return i + 1 }
fn.A[int]{1, 2, 3}.Map(AddOne).Print()
fn.A[int]{1, 2, 3}.M(AddOne).M(AddOne).Print()
// Output:
// [one three two]
// [one three two]
// 234345
}
func ExamplePrefix() {
fmt.Println(filter.Prefix([]string{"foo", "bar"}, "my"))
func ExampleA_Filter() {
GtTwo := func(i int) bool { return i > 2 }
LtFour := func(i int) bool { return i < 4 }
fn.A[int]{1, 2, 3, 4}.Filter(GtTwo).Print()
fn.A[int]{1, 2, 3, 4}.F(GtTwo).F(LtFour).Print()
// Output:
// [myfoo mybar]
// 343
}
func ExampleCleanPaths() {
paths := []string{
``,
`.`,
`./`,
`./thing`,
`/sub/../../thing`,
}
filter.Println(filter.CleanPaths(paths))
func ExampleA_Reduce() {
Sum := func(i int, a *int) { *a += i }
fmt.Println(*fn.A[int]{1, 2}.Reduce(Sum))
fmt.Println(*fn.A[int]{1, 2, 3, 4, 5}.R(Sum))
// Output:
// .
// .
// .
// /thing
// 3
// 15
}
func ExampleA_Print() {
fn.A[int]{1, 2}.Println()
fn.A[int]{1, 2}.P()
fn.A[int]{1, 2}.Printf("some: %v\n")
fn.A[int]{1, 2}.Print()
// Output:
// 1
// 2
// 1
// 2
// some: 1
// some: 2
// 12
}
func ExampleA_Log() {
log.SetOutput(os.Stdout)
log.SetFlags(0)
fn.A[int]{1, 2}.Log()
fn.A[int]{1, 2}.Logf("some: %v")
// Output:
// 1
// 2
// some: 1
// some: 2
}

Loading…
Cancel
Save