From c3603ccf96aac448d7d323e7487444b309b31136 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Mon, 15 Apr 2024 15:34:05 -0600 Subject: [PATCH] fn: add FindIdx function --- fn/slice.go | 16 ++++++++++++++-- fn/slice_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/fn/slice.go b/fn/slice.go index 32887bdb7..8f55cc159 100644 --- a/fn/slice.go +++ b/fn/slice.go @@ -53,7 +53,7 @@ func Map[A, B any](f func(A) B, s []A) []B { // Filter creates a new slice of values where all the members of the returned // slice pass the predicate that is supplied in the argument. -func Filter[A any](pred func(A) bool, s []A) []A { +func Filter[A any](pred Pred[A], s []A) []A { res := make([]A, 0) for _, val := range s { @@ -92,7 +92,7 @@ func Foldr[A, B any](f func(A, B) B, seed B, s []A) B { // Find returns the first value that passes the supplied predicate, or None if // the value wasn't found. -func Find[A any](pred func(A) bool, s []A) Option[A] { +func Find[A any](pred Pred[A], s []A) Option[A] { for _, val := range s { if pred(val) { return Some(val) @@ -102,6 +102,18 @@ func Find[A any](pred func(A) bool, s []A) Option[A] { return None[A]() } +// FindIdx returns the first value that passes the supplied predicate along with +// its index in the slice. If no satisfactory value is found, None is returned. +func FindIdx[A any](pred Pred[A], s []A) Option[T2[int, A]] { + for i, val := range s { + if pred(val) { + return Some(NewT2[int, A](i, val)) + } + } + + return None[T2[int, A]]() +} + // Flatten takes a slice of slices and returns a concatenation of those slices. func Flatten[A any](s [][]A) []A { sz := Foldr( diff --git a/fn/slice_test.go b/fn/slice_test.go index 47ca1f7f8..b91f35e48 100644 --- a/fn/slice_test.go +++ b/fn/slice_test.go @@ -340,3 +340,37 @@ func TestPropForEachConcOutperformsMapWhenExpensive(t *testing.T) { t.Fatal(err) } } + +func TestPropFindIdxFindIdentity(t *testing.T) { + f := func(div, mod uint8, s []uint8) bool { + if div == 0 || div == 1 { + return true + } + + pred := func(i uint8) bool { + return i%div == mod + } + + foundIdx := FindIdx(pred, s) + + // onlyVal :: Option[T2[A, B]] -> Option[B] + onlyVal := MapOption(func(t2 T2[int, uint8]) uint8 { + return t2.Second() + }) + + valuesEqual := Find(pred, s) == onlyVal(foundIdx) + + idxGetsVal := ElimOption( + foundIdx, + func() bool { return true }, + func(t2 T2[int, uint8]) bool { + return s[t2.First()] == t2.Second() + }) + + return valuesEqual && idxGetsVal + } + + if err := quick.Check(f, nil); err != nil { + t.Fatal(err) + } +}