From 4ed0046971e9c3c2397ff46cb193996116f248f1 Mon Sep 17 00:00:00 2001 From: "Dr. Carsten Leue" Date: Thu, 3 Aug 2023 14:32:46 +0200 Subject: [PATCH] fix: add uniq Signed-off-by: Dr. Carsten Leue --- iterator/stateless/generic/uniq.go | 62 ++++++++++++++++++++++++++++++ iterator/stateless/uniq.go | 32 +++++++++++++++ iterator/stateless/uniq_test.go | 31 +++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 iterator/stateless/generic/uniq.go create mode 100644 iterator/stateless/uniq.go create mode 100644 iterator/stateless/uniq_test.go diff --git a/iterator/stateless/generic/uniq.go b/iterator/stateless/generic/uniq.go new file mode 100644 index 0000000..315d677 --- /dev/null +++ b/iterator/stateless/generic/uniq.go @@ -0,0 +1,62 @@ +// 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" + T "github.com/IBM/fp-go/tuple" +) + +// addToMap makes a deep copy of a map and adds a value +func addToMap[A comparable](a A, m map[A]bool) map[A]bool { + cpy := make(map[A]bool, len(m)+1) + for k, v := range m { + cpy[k] = v + } + cpy[a] = true + return cpy +} + +func Uniq[AS ~func() O.Option[T.Tuple2[AS, A]], K comparable, A any](f func(A) K) func(as AS) AS { + + var recurse func(as AS, mp map[K]bool) AS + + recurse = func(as AS, mp map[K]bool) AS { + return F.Nullary2( + as, + O.Chain(func(a T.Tuple2[AS, A]) O.Option[T.Tuple2[AS, A]] { + return F.Pipe3( + a.F2, + f, + O.FromPredicate(func(k K) bool { + _, ok := mp[k] + return !ok + }), + O.Fold(recurse(a.F1, mp), func(k K) O.Option[T.Tuple2[AS, A]] { + return O.Of(T.MakeTuple2(recurse(a.F1, addToMap(k, mp)), a.F2)) + }), + ) + }), + ) + } + + return F.Bind2nd(recurse, make(map[K]bool, 0)) +} + +func StrictUniq[AS ~func() O.Option[T.Tuple2[AS, A]], A comparable](as AS) AS { + return Uniq[AS](F.Identity[A])(as) +} diff --git a/iterator/stateless/uniq.go b/iterator/stateless/uniq.go new file mode 100644 index 0000000..02a80e4 --- /dev/null +++ b/iterator/stateless/uniq.go @@ -0,0 +1,32 @@ +// 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 stateless + +import ( + G "github.com/IBM/fp-go/iterator/stateless/generic" +) + +// StrictUniq converts an [Iterator] or 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 +// 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) +} diff --git a/iterator/stateless/uniq_test.go b/iterator/stateless/uniq_test.go new file mode 100644 index 0000000..3507cd6 --- /dev/null +++ b/iterator/stateless/uniq_test.go @@ -0,0 +1,31 @@ +// 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 stateless + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUniq(t *testing.T) { + // iterator with duplicate items + dups := From(1, 2, 3, 1, 4, 5, 2) + + u := StrictUniq(dups) + + assert.Equal(t, ToArray(From(1, 2, 3, 4, 5)), ToArray(u)) +}