From 8bb006c74158743239552608150a6caaa5ff00dc Mon Sep 17 00:00:00 2001 From: Carsten Leue Date: Thu, 30 Nov 2023 09:03:16 +0100 Subject: [PATCH] fix: add a uniq method to arrays (#88) Signed-off-by: Dr. Carsten Leue --- array/generic/uniq.go | 32 ++++++++++++++++++++++++++++++++ array/uniq.go | 17 +++++++++++++++++ array/uniq_test.go | 14 ++++++++++++++ iterator/stateless/uniq.go | 4 ++-- 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 array/generic/uniq.go create mode 100644 array/uniq.go create mode 100644 array/uniq_test.go diff --git a/array/generic/uniq.go b/array/generic/uniq.go new file mode 100644 index 0000000..2733221 --- /dev/null +++ b/array/generic/uniq.go @@ -0,0 +1,32 @@ +package generic + +import F "github.com/IBM/fp-go/function" + +// StrictUniq converts an array of arbitrary items into an array or unique items +// where uniqueness is determined by the built-in uniqueness constraint +func StrictUniq[AS ~[]A, A comparable](as AS) AS { + return Uniq[AS](F.Identity[A])(as) +} + +// uniquePredUnsafe returns a predicate on a map for uniqueness +func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool { + lookup := make(map[K]bool) + return func(_ int, a A) bool { + k := f(a) + _, has := lookup[k] + if has { + return false + } + lookup[k] = true + return true + } +} + +// Uniq converts an array of arbitrary items into an array or unique items +// where uniqueness is determined based on a key extractor function +func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS { + return func(as AS) AS { + // we need to create a new predicate for each iteration + return filterWithIndex(as, uniquePredUnsafe(f)) + } +} diff --git a/array/uniq.go b/array/uniq.go new file mode 100644 index 0000000..2efabb4 --- /dev/null +++ b/array/uniq.go @@ -0,0 +1,17 @@ +package array + +import ( + G "github.com/IBM/fp-go/array/generic" +) + +// StrictUniq converts an array of arbitrary items into an array or unique items +// where uniqueness is determined by the built-in uniqueness constraint +func StrictUniq[A comparable](as []A) []A { + return G.StrictUniq[[]A](as) +} + +// Uniq converts an array of arbitrary items into an array or unique items +// where uniqueness is determined based on a key extractor function +func Uniq[A any, K comparable](f func(A) K) func(as []A) []A { + return G.Uniq[[]A](f) +} diff --git a/array/uniq_test.go b/array/uniq_test.go new file mode 100644 index 0000000..0b32749 --- /dev/null +++ b/array/uniq_test.go @@ -0,0 +1,14 @@ +package array + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUniq(t *testing.T) { + data := From(1, 2, 3, 2, 4, 1) + + uniq := StrictUniq(data) + assert.Equal(t, From(1, 2, 3, 4), uniq) +} diff --git a/iterator/stateless/uniq.go b/iterator/stateless/uniq.go index 02a80e4..8399692 100644 --- a/iterator/stateless/uniq.go +++ b/iterator/stateless/uniq.go @@ -19,13 +19,13 @@ import ( G "github.com/IBM/fp-go/iterator/stateless/generic" ) -// StrictUniq converts an [Iterator] or arbitrary items into an [Iterator] or unique items +// StrictUniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items // where uniqueness is determined by the built-in uniqueness constraint func StrictUniq[A comparable](as Iterator[A]) Iterator[A] { return G.StrictUniq[Iterator[A]](as) } -// Uniq converts an [Iterator] or arbitrary items into an [Iterator] or unique items +// Uniq converts an [Iterator] of arbitrary items into an [Iterator] or unique items // where uniqueness is determined based on a key extractor function func Uniq[A any, K comparable](f func(A) K) func(as Iterator[A]) Iterator[A] { return G.Uniq[Iterator[A], K](f)