diff --git a/set/set.go b/set/set.go index 98ec546..5edd720 100644 --- a/set/set.go +++ b/set/set.go @@ -67,6 +67,29 @@ func (s Of[T]) Equal(other Of[T]) bool { return true } +// 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 val, true + } + } + var zero T + return zero, false +} + // 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..65d1d2b 100644 --- a/set/set_test.go +++ b/set/set_test.go @@ -24,6 +24,19 @@ func TestSet(t *testing.T) { t.Errorf("got %v, want [1 2 3 4 5 6]", got) } + v1, exists1 := s.Find(func(val int) bool { return val > 3 }) + if !exists1 { + t.Errorf("Find(val > 3) failed") + } + if v1 <= 3 { + t.Errorf("Find(val > 3) failed with %d", v1) + } + + _, 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) i := Intersect(s, s2) if !reflect.DeepEqual(i, Of[int](map[int]struct{}{5: {}, 6: {}})) {