From e3fcd03b58c7a4d612a136c56d1fc4db6be47f57 Mon Sep 17 00:00:00 2001 From: Rick Date: Wed, 31 Jul 2024 23:26:39 +0100 Subject: [PATCH 1/2] Added set.Exists and set.Forall methods --- set/set.go | 24 ++++++++++++++++++++++++ set/set_test.go | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/set/set.go b/set/set.go index 5ad2f28..03d9a7e 100644 --- a/set/set.go +++ b/set/set.go @@ -67,6 +67,30 @@ func (s Of[T]) Equal(other Of[T]) bool { return true } +// Exists tests whether the set contains any value for which a function applied +// to the value returns true. If the function does not return true for any value +// in the set, Exists returns false. This is the logical inverse of Forall. +func (s Of[T]) Exists(f func(T) bool) bool { + for val := range s { + if f(val) { + return true + } + } + return false +} + +// Forall tests whether a given function returns true when applied to all values +// in the set. If so, Forall returns true, otherwise it returns false. This is the +// logical inverse of Exists. +func (s Of[T]) Forall(f func(T) bool) bool { + for val := range s { + if !f(val) { + return false + } + } + return true +} + // Each calls a function on each element of the set in an indeterminate order. // It is safe to add and remove items during a call to Each, // but that can affect the sequence of values seen later during the same Each call. diff --git a/set/set_test.go b/set/set_test.go index aa34624..a3b5f0c 100644 --- a/set/set_test.go +++ b/set/set_test.go @@ -24,6 +24,26 @@ func TestSet(t *testing.T) { t.Errorf("got %v, want [1 2 3 4 5 6]", got) } + exists1 := s.Exists(func(val int) bool { return val > 3 }) + if !exists1 { + t.Errorf("Exists(val > 3) failed") + } + + exists2 := s.Exists(func(val int) bool { return val > 10 }) + if exists2 { + t.Errorf("Exists(val > 103) failed") + } + + forall1 := s.Forall(func(val int) bool { return val >= 1 }) + if !forall1 { + t.Errorf("Forall(val >= 1) failed") + } + + forall2 := s.Forall(func(val int) bool { return val > 2 }) + if forall2 { + t.Errorf("Forall(val > 2) failed") + } + s2 := New[int](5, 6, 7, 8) i := Intersect(s, s2) if !reflect.DeepEqual(i, Of[int](map[int]struct{}{5: {}, 6: {}})) { From 7e2d81f974b8cbbe04881234269b851c4f075218 Mon Sep 17 00:00:00 2001 From: Rick Date: Thu, 1 Aug 2024 21:48:04 +0100 Subject: [PATCH 2/2] Replaced `Exists`/`Forall` with new `Find` method in `set` --- set/set.go | 35 +++++++++++++++++------------------ set/set_test.go | 21 +++++++-------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/set/set.go b/set/set.go index 03d9a7e..14de15a 100644 --- a/set/set.go +++ b/set/set.go @@ -67,28 +67,27 @@ func (s Of[T]) Equal(other Of[T]) bool { return true } -// Exists tests whether the set contains any value for which a function applied -// to the value returns true. If the function does not return true for any value -// in the set, Exists returns false. This is the logical inverse of Forall. -func (s Of[T]) Exists(f func(T) bool) bool { +// Find returns the first value for which a function applied to the value +// returns true. If the function does not return true for any value +// in the set, Find returns false and the zero value of T. +// +// if several set elements would match, the first match will be chosen +// arbitrarily because the iteration order is indeterminate. +// +// Find can also be used for two special cases: +// - To test whether any value exists that matches the predicate, +// a true boolean result is all that matters. +// - To test whether any value exists that does not match the predicate, +// in this case the inverse function should be supplied and +// a false result is all that matters. +func (s Of[T]) Find(f func(T) bool) (T, bool) { for val := range s { if f(val) { - return true + return val, true } } - return false -} - -// Forall tests whether a given function returns true when applied to all values -// in the set. If so, Forall returns true, otherwise it returns false. This is the -// logical inverse of Exists. -func (s Of[T]) Forall(f func(T) bool) bool { - for val := range s { - if !f(val) { - return false - } - } - return true + var zero T + return zero, false } // Each calls a function on each element of the set in an indeterminate order. diff --git a/set/set_test.go b/set/set_test.go index a3b5f0c..65d1d2b 100644 --- a/set/set_test.go +++ b/set/set_test.go @@ -24,24 +24,17 @@ func TestSet(t *testing.T) { t.Errorf("got %v, want [1 2 3 4 5 6]", got) } - exists1 := s.Exists(func(val int) bool { return val > 3 }) + v1, exists1 := s.Find(func(val int) bool { return val > 3 }) if !exists1 { - t.Errorf("Exists(val > 3) failed") + t.Errorf("Find(val > 3) failed") } - - exists2 := s.Exists(func(val int) bool { return val > 10 }) - if exists2 { - t.Errorf("Exists(val > 103) failed") + if v1 <= 3 { + t.Errorf("Find(val > 3) failed with %d", v1) } - forall1 := s.Forall(func(val int) bool { return val >= 1 }) - if !forall1 { - t.Errorf("Forall(val >= 1) failed") - } - - forall2 := s.Forall(func(val int) bool { return val > 2 }) - if forall2 { - t.Errorf("Forall(val > 2) failed") + _, exists2 := s.Find(func(val int) bool { return val > 10 }) + if exists2 { + t.Errorf("Find(val > 10) failed") } s2 := New[int](5, 6, 7, 8)