feat(sieve): add the remaining collection helpers and docs mentions
- Add TryMap, Filter, Reduce, KeyBy, GroupBy, Uniq, UniqBy, Partition and Find, plus the Set type built with SetOf (Has, Add, Slice). - Add unit tests at 100% statement coverage and a runnable example for every function and Set method. - Complete the module README: contracts, use cases, Pluck rationale, standard-library pointers and the full API reference. - docs/architecture/introduction.md: add a Utilities row for sieve. - docs/setup/coming-from-wintercms.md: map Laravel collection methods to sieve and narrow the not-provided row to the fluent collection object.
This commit is contained in:
@@ -20,3 +20,133 @@ func Map[S ~[]T, T, U any](s S, f func(T) U) []U {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// TryMap returns a new slice holding f applied to each element of s, in order.
|
||||
// It stops at the first error and returns nil together with that error,
|
||||
// unchanged; f is not called for the remaining elements. A caller that needs
|
||||
// the failing index wraps the error inside f. A nil or empty s yields a
|
||||
// non-nil empty slice and a nil error.
|
||||
func TryMap[S ~[]T, T, U any](s S, f func(T) (U, error)) ([]U, error) {
|
||||
out := make([]U, 0, len(s))
|
||||
for _, v := range s {
|
||||
u, err := f(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, u)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Filter returns a new slice holding the elements of s for which keep returns
|
||||
// true, in input order. The result has the caller's slice type. A nil or empty
|
||||
// s, or one with no matches, yields a non-nil empty slice.
|
||||
func Filter[S ~[]T, T any](s S, keep func(T) bool) S {
|
||||
out := make(S, 0)
|
||||
for _, v := range s {
|
||||
if keep(v) {
|
||||
out = append(out, v)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Reduce folds s from left to right: it starts with init and replaces the
|
||||
// accumulator with f(accumulator, element) for each element in order. The
|
||||
// accumulator type may differ from the element type. A nil or empty s returns
|
||||
// init unchanged.
|
||||
func Reduce[S ~[]T, T, A any](s S, init A, f func(A, T) A) A {
|
||||
acc := init
|
||||
for _, v := range s {
|
||||
acc = f(acc, v)
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
// KeyBy returns a new map from key(element) to element. When two elements
|
||||
// share a key, the later one wins. key is called once per element, in order.
|
||||
// A nil or empty s yields a non-nil empty map.
|
||||
func KeyBy[S ~[]T, T any, K comparable](s S, key func(T) K) map[K]T {
|
||||
out := make(map[K]T, len(s))
|
||||
for _, v := range s {
|
||||
out[key(v)] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GroupBy returns a new map from key(element) to the elements with that key.
|
||||
// Each group keeps input order and has the caller's slice type; groups are
|
||||
// independent of the input and of each other. key is called once per element,
|
||||
// in order. A nil or empty s yields a non-nil empty map.
|
||||
func GroupBy[S ~[]T, T any, K comparable](s S, key func(T) K) map[K]S {
|
||||
out := make(map[K]S)
|
||||
for _, v := range s {
|
||||
k := key(v)
|
||||
out[k] = append(out[k], v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Uniq returns a new slice holding the elements of s without duplicates,
|
||||
// keeping the first occurrence of each, in input order. The result has the
|
||||
// caller's slice type. A nil or empty s yields a non-nil empty slice.
|
||||
func Uniq[S ~[]T, T comparable](s S) S {
|
||||
out := make(S, 0, len(s))
|
||||
seen := make(map[T]struct{}, len(s))
|
||||
for _, v := range s {
|
||||
if _, ok := seen[v]; ok {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// UniqBy returns a new slice holding the elements of s whose key(element) has
|
||||
// not been seen before, keeping the first occurrence of each key, in input
|
||||
// order. key is called once per element. The result has the caller's slice
|
||||
// type. A nil or empty s yields a non-nil empty slice.
|
||||
func UniqBy[S ~[]T, T any, K comparable](s S, key func(T) K) S {
|
||||
out := make(S, 0, len(s))
|
||||
seen := make(map[K]struct{}, len(s))
|
||||
for _, v := range s {
|
||||
k := key(v)
|
||||
if _, ok := seen[k]; ok {
|
||||
continue
|
||||
}
|
||||
seen[k] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Partition splits s into two new slices: matched holds the elements for which
|
||||
// match returns true and rest holds the others, both in input order and both
|
||||
// with the caller's slice type. match is called once per element. Both results
|
||||
// are non-nil, even when empty, and for a nil or empty s.
|
||||
func Partition[S ~[]T, T any](s S, match func(T) bool) (matched, rest S) {
|
||||
matched = make(S, 0)
|
||||
rest = make(S, 0)
|
||||
for _, v := range s {
|
||||
if match(v) {
|
||||
matched = append(matched, v)
|
||||
} else {
|
||||
rest = append(rest, v)
|
||||
}
|
||||
}
|
||||
return matched, rest
|
||||
}
|
||||
|
||||
// Find returns the first element of s for which match returns true, and true.
|
||||
// match is not called after the first match. When nothing matches, or s is nil
|
||||
// or empty, Find returns the zero value of T and false.
|
||||
func Find[S ~[]T, T any](s S, match func(T) bool) (T, bool) {
|
||||
for _, v := range s {
|
||||
if match(v) {
|
||||
return v, true
|
||||
}
|
||||
}
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user