mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
fix: add reduce and filter (#79)
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
30
array/any.go
Normal file
30
array/any.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||||
|
func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool {
|
||||||
|
return G.AnyWithIndex[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any tests if any of the elements in the array matches the predicate
|
||||||
|
func Any[A any](pred func(A) bool) func([]A) bool {
|
||||||
|
return G.Any[[]A](pred)
|
||||||
|
}
|
||||||
30
array/any_test.go
Normal file
30
array/any_test.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAny(t *testing.T) {
|
||||||
|
anyBool := Any(F.Identity[bool])
|
||||||
|
|
||||||
|
assert.True(t, anyBool(From(false, true, false)))
|
||||||
|
assert.False(t, anyBool(From(false, false, false)))
|
||||||
|
}
|
||||||
@@ -60,18 +60,6 @@ func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
|||||||
return F.Bind2nd(MonadMapRef[A, B], f)
|
return F.Bind2nd(MonadMapRef[A, B], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filter[A any](fa []A, pred func(A) bool) []A {
|
|
||||||
var result []A
|
|
||||||
count := len(fa)
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
a := fa[i]
|
|
||||||
if pred(a) {
|
|
||||||
result = append(result, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
||||||
var result []A
|
var result []A
|
||||||
count := len(fa)
|
count := len(fa)
|
||||||
@@ -96,23 +84,38 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter returns a new array with all elements from the original array that match a predicate
|
||||||
func Filter[A any](pred func(A) bool) func([]A) []A {
|
func Filter[A any](pred func(A) bool) func([]A) []A {
|
||||||
return F.Bind2nd(filter[A], pred)
|
return G.Filter[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
||||||
|
func FilterWithIndex[A any](pred func(int, A) bool) func([]A) []A {
|
||||||
|
return G.FilterWithIndex[[]A](pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
|
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
|
||||||
return F.Bind2nd(filterRef[A], pred)
|
return F.Bind2nd(filterRef[A], pred)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
|
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
||||||
return G.MonadFilterMap[[]A, []B](fa, f)
|
return G.MonadFilterMap[[]A, []B](fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterChain maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
|
||||||
func FilterMap[A, B any](f func(a A) O.Option[B]) func([]A) []B {
|
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||||
|
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
|
||||||
return G.FilterMap[[]A, []B](f)
|
return G.FilterMap[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||||
|
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
|
||||||
|
return G.FilterMapWithIndex[[]A, []B](f)
|
||||||
|
}
|
||||||
|
|
||||||
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
||||||
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
||||||
return G.FilterChain[[]A](f)
|
return G.FilterChain[[]A](f)
|
||||||
@@ -134,9 +137,19 @@ func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
|
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
|
||||||
return func(as []A) B {
|
return G.Reduce[[]A](f, initial)
|
||||||
return array.Reduce(as, f, initial)
|
}
|
||||||
}
|
|
||||||
|
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B {
|
||||||
|
return G.ReduceWithIndex[[]A](f, initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B {
|
||||||
|
return G.ReduceRight[[]A](f, initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B {
|
||||||
|
return G.ReduceRightWithIndex[[]A](f, initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
|
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
|
||||||
|
|||||||
@@ -59,6 +59,17 @@ func TestMap(t *testing.T) {
|
|||||||
assert.Equal(t, dst, []string{"A", "B", "C"})
|
assert.Equal(t, dst, []string{"A", "B", "C"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReduceRight(t *testing.T) {
|
||||||
|
values := From("a", "b", "c")
|
||||||
|
f := func(a, acc string) string {
|
||||||
|
return fmt.Sprintf("%s%s", acc, a)
|
||||||
|
}
|
||||||
|
b := ""
|
||||||
|
|
||||||
|
assert.Equal(t, "cba", ReduceRight(f, b)(values))
|
||||||
|
assert.Equal(t, "", ReduceRight(f, b)(Empty[string]()))
|
||||||
|
}
|
||||||
|
|
||||||
func TestReduce(t *testing.T) {
|
func TestReduce(t *testing.T) {
|
||||||
|
|
||||||
values := MakeBy(101, F.Identity[int])
|
values := MakeBy(101, F.Identity[int])
|
||||||
|
|||||||
77
array/example_any_test.go
Normal file
77
array/example_any_test.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Example_any() {
|
||||||
|
|
||||||
|
pred := func(val int) bool {
|
||||||
|
return val&2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data1 := From(1, 2, 3)
|
||||||
|
|
||||||
|
fmt.Println(Any(pred)(data1))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_any_filter() {
|
||||||
|
|
||||||
|
pred := func(val int) bool {
|
||||||
|
return val&2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data1 := From(1, 2, 3)
|
||||||
|
|
||||||
|
// Any tests if any of the entries in the array matches the condition
|
||||||
|
Any := F.Flow2(
|
||||||
|
Filter(pred),
|
||||||
|
IsNonEmpty[int],
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(Any(data1))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_any_find() {
|
||||||
|
|
||||||
|
pred := func(val int) bool {
|
||||||
|
return val&2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data1 := From(1, 2, 3)
|
||||||
|
|
||||||
|
// Any tests if any of the entries in the array matches the condition
|
||||||
|
Any := F.Flow2(
|
||||||
|
FindFirst(pred),
|
||||||
|
O.IsSome[int],
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(Any(data1))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
|
}
|
||||||
55
array/example_find_test.go
Normal file
55
array/example_find_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Example_find() {
|
||||||
|
|
||||||
|
pred := func(val int) bool {
|
||||||
|
return val&2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data1 := From(1, 2, 3)
|
||||||
|
|
||||||
|
fmt.Println(FindFirst(pred)(data1))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Some[int](1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_find_filter() {
|
||||||
|
|
||||||
|
pred := func(val int) bool {
|
||||||
|
return val&2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data1 := From(1, 2, 3)
|
||||||
|
|
||||||
|
Find := F.Flow2(
|
||||||
|
Filter(pred),
|
||||||
|
Head[int],
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println(Find(data1))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Some[int](1)
|
||||||
|
}
|
||||||
61
array/find.go
Normal file
61
array/find.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||||
|
return G.FindFirst[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||||
|
return G.FindFirstWithIndex[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||||
|
return G.FindFirstMap[[]A](sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||||
|
return G.FindFirstMapWithIndex[[]A](sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLast finds the Last element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||||
|
return G.FindLast[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastWithIndex finds the Last element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||||
|
return G.FindLastWithIndex[[]A](pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastMap finds the Last element returned by an [O.Option] based selector function
|
||||||
|
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||||
|
return G.FindLastMap[[]A](sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastMapWithIndex finds the Last element returned by an [O.Option] based selector function
|
||||||
|
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||||
|
return G.FindLastMapWithIndex[[]A](sel)
|
||||||
|
}
|
||||||
34
array/generic/any.go
Normal file
34
array/generic/any.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||||
|
func AnyWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) bool {
|
||||||
|
return F.Flow2(
|
||||||
|
FindFirstWithIndex[AS](pred),
|
||||||
|
O.IsSome[A],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any tests if any of the elements in the array matches the predicate
|
||||||
|
func Any[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) bool {
|
||||||
|
return AnyWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
@@ -29,14 +29,46 @@ func Of[GA ~[]A, A any](value A) GA {
|
|||||||
return GA{value}
|
return GA{value}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B {
|
||||||
|
return func(as GA) B {
|
||||||
|
return MonadReduce[GA](as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B {
|
||||||
|
return func(as GA) B {
|
||||||
|
return MonadReduceWithIndex[GA](as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B {
|
||||||
|
return func(as GA) B {
|
||||||
|
return MonadReduceRight[GA](as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B {
|
||||||
|
return func(as GA) B {
|
||||||
|
return MonadReduceRightWithIndex[GA](as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||||
return array.Reduce(fa, f, initial)
|
return array.Reduce(fa, f, initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||||
return array.ReduceWithIndex(fa, f, initial)
|
return array.ReduceWithIndex(fa, f, initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||||
|
return array.ReduceRight(fa, f, initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||||
|
return array.ReduceRightWithIndex(fa, f, initial)
|
||||||
|
}
|
||||||
|
|
||||||
// From constructs an array from a set of variadic arguments
|
// From constructs an array from a set of variadic arguments
|
||||||
func From[GA ~[]A, A any](data ...A) GA {
|
func From[GA ~[]A, A any](data ...A) GA {
|
||||||
return data
|
return data
|
||||||
@@ -122,16 +154,44 @@ func Size[GA ~[]A, A any](as GA) int {
|
|||||||
return len(as)
|
return len(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||||
return array.Reduce(fa, func(bs GB, a A) GB {
|
return array.Reduce(fa, func(bs GB, a A) GB {
|
||||||
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||||
}, Empty[GB]())
|
}, Empty[GB]())
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||||
|
return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB {
|
||||||
|
return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||||
|
}, Empty[GB]())
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||||
return filterMap[GA, GB](fa, f)
|
return filterMap[GA, GB](fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||||
|
return filterMapWithIndex[GA, GB](fa, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS {
|
||||||
|
result := make(AS, 0, len(fa))
|
||||||
|
for i, a := range fa {
|
||||||
|
if pred(i, a) {
|
||||||
|
result = append(result, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS {
|
||||||
|
return F.Bind2nd(filterWithIndex[AS, PRED, A], pred)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS {
|
||||||
|
return FilterWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
|
|
||||||
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
|
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
FilterMap[GA, []GB](f),
|
FilterMap[GA, []GB](f),
|
||||||
@@ -143,10 +203,14 @@ func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA {
|
|||||||
return MonadChain(mma, F.Identity[GA])
|
return MonadChain(mma, F.Identity[GA])
|
||||||
}
|
}
|
||||||
|
|
||||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[B]) func(GA) GB {
|
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
|
||||||
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB {
|
||||||
|
return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
|
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
|
||||||
left := Empty[GA]()
|
left := Empty[GA]()
|
||||||
right := Empty[GA]()
|
right := Empty[GA]()
|
||||||
|
|||||||
97
array/generic/find.go
Normal file
97
array/generic/find.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindFirstWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||||
|
none := O.None[A]()
|
||||||
|
return func(as AS) O.Option[A] {
|
||||||
|
for i, a := range as {
|
||||||
|
if pred(i, a) {
|
||||||
|
return O.Some(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||||
|
return FindFirstWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||||
|
none := O.None[B]()
|
||||||
|
return func(as AS) O.Option[B] {
|
||||||
|
count := len(as)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
out := pred(i, as[i])
|
||||||
|
if O.IsSome(out) {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindFirstMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||||
|
return FindFirstMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindLastWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||||
|
none := O.None[A]()
|
||||||
|
return func(as AS) O.Option[A] {
|
||||||
|
for i := len(as) - 1; i >= 0; i-- {
|
||||||
|
a := as[i]
|
||||||
|
if pred(i, a) {
|
||||||
|
return O.Some(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLast finds the first element which satisfies a predicate (or a refinement) function
|
||||||
|
func FindLast[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||||
|
return FindLastWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindLastMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||||
|
none := O.None[B]()
|
||||||
|
return func(as AS) O.Option[B] {
|
||||||
|
for i := len(as) - 1; i >= 0; i-- {
|
||||||
|
out := pred(i, as[i])
|
||||||
|
if O.IsSome(out) {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLastMap finds the first element returned by an [O.Option] based selector function
|
||||||
|
func FindLastMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||||
|
return FindLastMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||||
|
}
|
||||||
@@ -51,6 +51,24 @@ func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B
|
|||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||||
|
current := initial
|
||||||
|
count := len(fa)
|
||||||
|
for i := count - 1; i >= 0; i-- {
|
||||||
|
current = f(fa[i], current)
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||||
|
current := initial
|
||||||
|
count := len(fa)
|
||||||
|
for i := count - 1; i >= 0; i-- {
|
||||||
|
current = f(i, fa[i], current)
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
func Append[GA ~[]A, A any](as GA, a A) GA {
|
func Append[GA ~[]A, A any](as GA, a A) GA {
|
||||||
return append(as, a)
|
return append(as, a)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func TestRetryHttp(t *testing.T) {
|
|||||||
check := E.Fold(
|
check := E.Fold(
|
||||||
F.Flow2(
|
F.Flow2(
|
||||||
errors.As[*net.DNSError](),
|
errors.As[*net.DNSError](),
|
||||||
O.Fold(F.Constant(false), F.Constant1[*net.DNSError](true)),
|
O.IsSome[*net.DNSError],
|
||||||
),
|
),
|
||||||
F.Constant1[*PostItem](false),
|
F.Constant1[*PostItem](false),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ func Any[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) bool, U any](pred FC
|
|||||||
return F.Flow3(
|
return F.Flow3(
|
||||||
Filter[GU](pred),
|
Filter[GU](pred),
|
||||||
First[GU],
|
First[GU],
|
||||||
O.Fold(F.ConstFalse, F.Constant1[U](true)),
|
O.IsSome[U],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user