mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: implement FilterChain
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
17
record/doc.go
Normal file
17
record/doc.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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 record contains monadic operations for maps as well as a rich set of utility functions
|
||||
package record
|
@@ -16,6 +16,7 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
@@ -26,3 +27,17 @@ func UnionMonoid[N ~map[K]V, K comparable, V any](s S.Semigroup[V]) M.Monoid[N]
|
||||
Empty[N](),
|
||||
)
|
||||
}
|
||||
|
||||
func UnionLastMonoid[N ~map[K]V, K comparable, V any]() M.Monoid[N] {
|
||||
return M.MakeMonoid(
|
||||
unionLast[N],
|
||||
Empty[N](),
|
||||
)
|
||||
}
|
||||
|
||||
func UnionFirstMonoid[N ~map[K]V, K comparable, V any]() M.Monoid[N] {
|
||||
return M.MakeMonoid(
|
||||
F.Swap(unionLast[N]),
|
||||
Empty[N](),
|
||||
)
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
G "github.com/IBM/fp-go/internal/record"
|
||||
Mg "github.com/IBM/fp-go/magma"
|
||||
Mo "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
@@ -82,6 +83,34 @@ func MonadMap[M ~map[K]V, N ~map[K]R, K comparable, V, R any](r M, f func(V) R)
|
||||
return MonadMapWithIndex[M, N](r, F.Ignore1of2[K](f))
|
||||
}
|
||||
|
||||
func MonadChainWithIndex[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N], r M, f func(K, V1) N) N {
|
||||
return G.ReduceWithIndex(r, func(k K, dst N, b V1) N {
|
||||
return m.Concat(dst, f(k, b))
|
||||
}, m.Empty())
|
||||
}
|
||||
|
||||
func MonadChain[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N], r M, f func(V1) N) N {
|
||||
return G.Reduce(r, func(dst N, b V1) N {
|
||||
return m.Concat(dst, f(b))
|
||||
}, m.Empty())
|
||||
}
|
||||
|
||||
func ChainWithIndex[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N]) func(func(K, V1) N) func(M) N {
|
||||
return func(f func(K, V1) N) func(M) N {
|
||||
return func(ma M) N {
|
||||
return MonadChainWithIndex(m, ma, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Chain[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N]) func(func(V1) N) func(M) N {
|
||||
return func(f func(V1) N) func(M) N {
|
||||
return func(ma M) N {
|
||||
return MonadChain(m, ma, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MonadMapWithIndex[M ~map[K]V, N ~map[K]R, K comparable, V, R any](r M, f func(K, V) R) N {
|
||||
return G.ReduceWithIndex(r, func(k K, dst N, v V) N {
|
||||
return upsertAtReadWrite(dst, k, f(k, v))
|
||||
@@ -114,15 +143,14 @@ func MapRefWithIndex[M ~map[K]V, N ~map[K]R, K comparable, V, R any](f func(K, *
|
||||
return F.Bind2nd(MonadMapRefWithIndex[M, N, K, V, R], f)
|
||||
}
|
||||
|
||||
func lookup[M ~map[K]V, K comparable, V any](r M, k K) O.Option[V] {
|
||||
if val, ok := r[k]; ok {
|
||||
return O.Some(val)
|
||||
}
|
||||
return O.None[V]()
|
||||
}
|
||||
|
||||
func Lookup[M ~map[K]V, K comparable, V any](k K) func(M) O.Option[V] {
|
||||
return F.Bind2nd(lookup[M, K, V], k)
|
||||
n := O.None[V]()
|
||||
return func(m M) O.Option[V] {
|
||||
if val, ok := m[k]; ok {
|
||||
return O.Some(val)
|
||||
}
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
func Has[M ~map[K]V, K comparable, V any](k K, r M) bool {
|
||||
@@ -161,6 +189,31 @@ func union[M ~map[K]V, K comparable, V any](m Mg.Magma[V], left M, right M) M {
|
||||
return result
|
||||
}
|
||||
|
||||
func unionLast[M ~map[K]V, K comparable, V any](left M, right M) M {
|
||||
lenLeft := len(left)
|
||||
|
||||
if lenLeft == 0 {
|
||||
return right
|
||||
}
|
||||
|
||||
lenRight := len(right)
|
||||
if lenRight == 0 {
|
||||
return left
|
||||
}
|
||||
|
||||
result := make(M, lenLeft+lenRight)
|
||||
|
||||
for k, v := range left {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
for k, v := range right {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func Union[M ~map[K]V, K comparable, V any](m Mg.Magma[V]) func(M) func(M) M {
|
||||
return func(right M) func(M) M {
|
||||
return func(left M) M {
|
||||
@@ -169,6 +222,22 @@ func Union[M ~map[K]V, K comparable, V any](m Mg.Magma[V]) func(M) func(M) M {
|
||||
}
|
||||
}
|
||||
|
||||
func UnionLast[M ~map[K]V, K comparable, V any](right M) func(M) M {
|
||||
return func(left M) M {
|
||||
return unionLast(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
func Merge[M ~map[K]V, K comparable, V any](right M) func(M) M {
|
||||
return UnionLast(right)
|
||||
}
|
||||
|
||||
func UnionFirst[M ~map[K]V, K comparable, V any](right M) func(M) M {
|
||||
return func(left M) M {
|
||||
return unionLast(right, left)
|
||||
}
|
||||
}
|
||||
|
||||
func Empty[M ~map[K]V, K comparable, V any]() M {
|
||||
return make(M)
|
||||
}
|
||||
@@ -269,6 +338,33 @@ func FilterMap[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](f func(V1) O.
|
||||
return F.Bind2nd(filterMapWithIndex[M, N, K, V1, V2], F.Ignore1of2[K](f))
|
||||
}
|
||||
|
||||
// Flatten converts a nested map into a regular map
|
||||
func Flatten[M ~map[K]N, N ~map[K]V, K comparable, V any](m Mo.Monoid[N]) func(M) N {
|
||||
return Chain[M, N](m)(F.Identity[N])
|
||||
}
|
||||
|
||||
// FilterChainWithIndex creates a new map with only the elements for which the transformation function creates a Some
|
||||
func FilterChainWithIndex[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N]) func(func(K, V1) O.Option[N]) func(M) N {
|
||||
flatten := Flatten[map[K]N, N](m)
|
||||
return func(f func(K, V1) O.Option[N]) func(M) N {
|
||||
return F.Flow2(
|
||||
FilterMapWithIndex[M, map[K]N](f),
|
||||
flatten,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// FilterChain creates a new map with only the elements for which the transformation function creates a Some
|
||||
func FilterChain[M ~map[K]V1, N ~map[K]V2, K comparable, V1, V2 any](m Mo.Monoid[N]) func(func(V1) O.Option[N]) func(M) N {
|
||||
flatten := Flatten[map[K]N, N](m)
|
||||
return func(f func(V1) O.Option[N]) func(M) N {
|
||||
return F.Flow2(
|
||||
FilterMap[M, map[K]N](f),
|
||||
flatten,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// IsNil checks if the map is set to nil
|
||||
func IsNil[M ~map[K]V, K comparable, V any](m M) bool {
|
||||
return m == nil
|
||||
|
@@ -20,8 +20,19 @@ import (
|
||||
)
|
||||
|
||||
func UnionSemigroup[N ~map[K]V, K comparable, V any](s S.Semigroup[V]) S.Semigroup[N] {
|
||||
union := Union[N, K, V](s)
|
||||
return S.MakeSemigroup(func(first N, second N) N {
|
||||
return union(second)(first)
|
||||
return union(s, first, second)
|
||||
})
|
||||
}
|
||||
|
||||
func UnionLastSemigroup[N ~map[K]V, K comparable, V any]() S.Semigroup[N] {
|
||||
return S.MakeSemigroup(func(first N, second N) N {
|
||||
return unionLast(first, second)
|
||||
})
|
||||
}
|
||||
|
||||
func UnionFirstSemigroup[N ~map[K]V, K comparable, V any]() S.Semigroup[N] {
|
||||
return S.MakeSemigroup(func(first N, second N) N {
|
||||
return unionLast(second, first)
|
||||
})
|
||||
}
|
||||
|
@@ -21,6 +21,22 @@ import (
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
// UnionMonoid computes the union of two maps of the same type
|
||||
func UnionMonoid[K comparable, V any](s S.Semigroup[V]) M.Monoid[map[K]V] {
|
||||
return G.UnionMonoid[map[K]V](s)
|
||||
}
|
||||
|
||||
// UnionLastMonoid computes the union of two maps of the same type giving the last map precedence
|
||||
func UnionLastMonoid[K comparable, V any]() M.Monoid[map[K]V] {
|
||||
return G.UnionLastMonoid[map[K]V]()
|
||||
}
|
||||
|
||||
// UnionFirstMonoid computes the union of two maps of the same type giving the first map precedence
|
||||
func UnionFirstMonoid[K comparable, V any]() M.Monoid[map[K]V] {
|
||||
return G.UnionFirstMonoid[map[K]V]()
|
||||
}
|
||||
|
||||
// MergeMonoid computes the union of two maps of the same type giving the last map precedence
|
||||
func MergeMonoid[K comparable, V any]() M.Monoid[map[K]V] {
|
||||
return G.UnionLastMonoid[map[K]V]()
|
||||
}
|
||||
|
@@ -17,27 +17,33 @@ package record
|
||||
|
||||
import (
|
||||
Mg "github.com/IBM/fp-go/magma"
|
||||
Mo "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
G "github.com/IBM/fp-go/record/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// IsEmpty tests if a map is empty
|
||||
func IsEmpty[K comparable, V any](r map[K]V) bool {
|
||||
return G.IsEmpty(r)
|
||||
}
|
||||
|
||||
// IsNonEmpty tests if a map is not empty
|
||||
func IsNonEmpty[K comparable, V any](r map[K]V) bool {
|
||||
return G.IsNonEmpty(r)
|
||||
}
|
||||
|
||||
// Keys returns the key in a map
|
||||
func Keys[K comparable, V any](r map[K]V) []K {
|
||||
return G.Keys[map[K]V, []K](r)
|
||||
}
|
||||
|
||||
// Values returns the values in a map
|
||||
func Values[K comparable, V any](r map[K]V) []V {
|
||||
return G.Values[map[K]V, []V](r)
|
||||
}
|
||||
|
||||
// Collect applies a collector function to the key value pairs in a map and returns the result as an array
|
||||
func Collect[K comparable, V, R any](f func(K, V) R) func(map[K]V) []R {
|
||||
return G.Collect[map[K]V, []R](f)
|
||||
}
|
||||
@@ -90,10 +96,12 @@ func MapRefWithIndex[K comparable, V, R any](f func(K, *V) R) func(map[K]V) map[
|
||||
return G.MapRefWithIndex[map[K]V, map[K]R](f)
|
||||
}
|
||||
|
||||
// Lookup returns the entry for a key in a map if it exists
|
||||
func Lookup[K comparable, V any](k K) func(map[K]V) O.Option[V] {
|
||||
return G.Lookup[map[K]V](k)
|
||||
}
|
||||
|
||||
// Has tests if a key is contained in a map
|
||||
func Has[K comparable, V any](k K, r map[K]V) bool {
|
||||
return G.Has(k, r)
|
||||
}
|
||||
@@ -102,10 +110,17 @@ func Union[K comparable, V any](m Mg.Magma[V]) func(map[K]V) func(map[K]V) map[K
|
||||
return G.Union[map[K]V](m)
|
||||
}
|
||||
|
||||
// Merge combines two maps giving the values in the right one precedence. Also refer to [MergeMonoid]
|
||||
func Merge[K comparable, V any](right map[K]V) func(map[K]V) map[K]V {
|
||||
return G.Merge[map[K]V](right)
|
||||
}
|
||||
|
||||
// Empty creates an empty map
|
||||
func Empty[K comparable, V any]() map[K]V {
|
||||
return G.Empty[map[K]V]()
|
||||
}
|
||||
|
||||
// Size returns the number of elements in a map
|
||||
func Size[K comparable, V any](r map[K]V) int {
|
||||
return G.Size(r)
|
||||
}
|
||||
@@ -130,6 +145,7 @@ func DeleteAt[K comparable, V any](k K) func(map[K]V) map[K]V {
|
||||
return G.DeleteAt[map[K]V](k)
|
||||
}
|
||||
|
||||
// Singleton creates a new map with a single entry
|
||||
func Singleton[K comparable, V any](k K, v V) map[K]V {
|
||||
return G.Singleton[map[K]V](k, v)
|
||||
}
|
||||
@@ -168,3 +184,34 @@ func IsNonNil[K comparable, V any](m map[K]V) bool {
|
||||
func ConstNil[K comparable, V any]() map[K]V {
|
||||
return (map[K]V)(nil)
|
||||
}
|
||||
|
||||
func MonadChainWithIndex[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2], r map[K]V1, f func(K, V1) map[K]V2) map[K]V2 {
|
||||
return G.MonadChainWithIndex(m, r, f)
|
||||
}
|
||||
|
||||
func MonadChain[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2], r map[K]V1, f func(V1) map[K]V2) map[K]V2 {
|
||||
return G.MonadChain(m, r, f)
|
||||
}
|
||||
|
||||
func ChainWithIndex[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2]) func(func(K, V1) map[K]V2) func(map[K]V1) map[K]V2 {
|
||||
return G.ChainWithIndex[map[K]V1](m)
|
||||
}
|
||||
|
||||
func Chain[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2]) func(func(V1) map[K]V2) func(map[K]V1) map[K]V2 {
|
||||
return G.Chain[map[K]V1](m)
|
||||
}
|
||||
|
||||
// Flatten converts a nested map into a regular map
|
||||
func Flatten[K comparable, V any](m Mo.Monoid[map[K]V]) func(map[K]map[K]V) map[K]V {
|
||||
return G.Flatten[map[K]map[K]V](m)
|
||||
}
|
||||
|
||||
// FilterChainWithIndex creates a new map with only the elements for which the transformation function creates a Some
|
||||
func FilterChainWithIndex[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2]) func(func(K, V1) O.Option[map[K]V2]) func(map[K]V1) map[K]V2 {
|
||||
return G.FilterChainWithIndex[map[K]V1](m)
|
||||
}
|
||||
|
||||
// FilterChain creates a new map with only the elements for which the transformation function creates a Some
|
||||
func FilterChain[V1 any, K comparable, V2 any](m Mo.Monoid[map[K]V2]) func(func(V1) O.Option[map[K]V2]) func(map[K]V1) map[K]V2 {
|
||||
return G.FilterChain[map[K]V1](m)
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
@@ -71,3 +72,30 @@ func TestLookup(t *testing.T) {
|
||||
assert.Equal(t, O.Some("a"), Lookup[string, string]("a")(data))
|
||||
assert.Equal(t, O.None[string](), Lookup[string, string]("a1")(data))
|
||||
}
|
||||
|
||||
func TestFilterChain(t *testing.T) {
|
||||
src := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
f := func(k string, value int) O.Option[map[string]string] {
|
||||
if value%2 != 0 {
|
||||
return O.Of(map[string]string{
|
||||
k: fmt.Sprintf("%s%d", k, value),
|
||||
})
|
||||
}
|
||||
return O.None[map[string]string]()
|
||||
}
|
||||
|
||||
// monoid
|
||||
monoid := MergeMonoid[string, string]()
|
||||
|
||||
res := FilterChainWithIndex[int](monoid)(f)(src)
|
||||
|
||||
assert.Equal(t, map[string]string{
|
||||
"a": "a1",
|
||||
"c": "c3",
|
||||
}, res)
|
||||
}
|
||||
|
@@ -22,3 +22,11 @@ import (
|
||||
func UnionSemigroup[K comparable, V any](s S.Semigroup[V]) S.Semigroup[map[K]V] {
|
||||
return G.UnionSemigroup[map[K]V](s)
|
||||
}
|
||||
|
||||
func UnionLastSemigroup[K comparable, V any]() S.Semigroup[map[K]V] {
|
||||
return G.UnionLastSemigroup[map[K]V]()
|
||||
}
|
||||
|
||||
func UnionFirstSemigroup[K comparable, V any]() S.Semigroup[map[K]V] {
|
||||
return G.UnionFirstSemigroup[map[K]V]()
|
||||
}
|
||||
|
Reference in New Issue
Block a user