From e0b4448d0fd64edca6daf73bd7e4873bb5ea1da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20M=C3=BCller?= Date: Wed, 15 Sep 2021 11:07:04 +0200 Subject: [PATCH] Remove restriction of bsearch block output type --- spec/std/array_spec.cr | 1 + spec/std/range_spec.cr | 2 ++ src/indexable.cr | 30 ++++++++++++++++-------------- src/range/bsearch.cr | 16 ++++++++-------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/spec/std/array_spec.cr b/spec/std/array_spec.cr index 9c78e7f26bdc..075f7e7d5ca4 100644 --- a/spec/std/array_spec.cr +++ b/spec/std/array_spec.cr @@ -456,6 +456,7 @@ describe "Array" do it "find the element by using binary search" do [2, 5, 7, 10].bsearch { |x| x >= 4 }.should eq 5 [2, 5, 7, 10].bsearch { |x| x > 10 }.should be_nil + [2, 5, 7, 10].bsearch { |x| x >= 4 ? 1 : nil }.should eq 5 end it "find the index by using binary search" do diff --git a/spec/std/range_spec.cr b/spec/std/range_spec.cr index 14e2e0206696..f64f6b32ce9a 100644 --- a/spec/std/range_spec.cr +++ b/spec/std/range_spec.cr @@ -145,6 +145,8 @@ describe "Range" do (0...ary.size).bsearch { |i| true }.should eq 0 (0...ary.size).bsearch { |i| false }.should eq nil + (0...ary.size).bsearch { |i| ary[i] >= 10 ? 1 : nil }.should eq 4 + ary = [0, 100, 100, 100, 200] (0...ary.size).bsearch { |i| ary[i] >= 100 }.should eq 1 diff --git a/src/indexable.cr b/src/indexable.cr index cb81a487f847..622b76a1d971 100644 --- a/src/indexable.cr +++ b/src/indexable.cr @@ -133,40 +133,42 @@ module Indexable(T) end # By using binary search, returns the first element - # for which the passed block returns `true`. + # for which the passed block returns a truthy value. # - # If the block returns `false`, the finding element exists - # behind. If the block returns `true`, the finding element - # is itself or exists in front. + # If the block returns a falsey value, the element to be found lies + # behind. If the block returns a truthy value, the element to be found + # is itself or lies in front. # - # Binary search needs sorted array, so `self` has to be sorted. + # Binary search needs the collection to be sorted in regards to the search + # criterion. # - # Returns `nil` if the block didn't return `true` for any element. + # Returns `nil` if the block didn't return a truthy value for any element. # # ``` # [2, 5, 7, 10].bsearch { |x| x >= 4 } # => 5 # [2, 5, 7, 10].bsearch { |x| x > 10 } # => nil # ``` - def bsearch(&block : T -> Bool) + def bsearch(&block : T -> _) bsearch_index { |value| yield value }.try { |index| unsafe_fetch(index) } end # By using binary search, returns the index of the first element - # for which the passed block returns `true`. + # for which the passed block returns a truthy value. # - # If the block returns `false`, the finding element exists - # behind. If the block returns `true`, the finding element - # is itself or exists in front. + # If the block returns a falsey value, the element to be found lies + # behind. If the block returns a truthy value, the element to be found + # is itself or lies in front. # - # Binary search needs sorted array, so `self` has to be sorted. + # Binary search needs the collection to be sorted in regards to the search + # criterion. # - # Returns `nil` if the block didn't return `true` for any element. + # Returns `nil` if the block didn't return a truthy value for any element. # # ``` # [2, 5, 7, 10].bsearch_index { |x, i| x >= 4 } # => 1 # [2, 5, 7, 10].bsearch_index { |x, i| x > 10 } # => nil # ``` - def bsearch_index(&block : T, Int32 -> Bool) + def bsearch_index(&block : T, Int32 -> _) (0...size).bsearch { |index| yield unsafe_fetch(index), index } end diff --git a/src/range/bsearch.cr b/src/range/bsearch.cr index 641cf5774eed..fd6994e7580a 100644 --- a/src/range/bsearch.cr +++ b/src/range/bsearch.cr @@ -68,20 +68,20 @@ {% end %} struct Range(B, E) - # By using binary search, returns the first value - # for which the passed block returns `true`. + # By using binary search, returns the first element + # for which the passed block returns a truthy value. # - # If the block returns `false`, the finding value exists - # behind. If the block returns `true`, the finding value - # is itself or exists in front. + # If the block returns a falsey value, the element to be found lies + # behind. If the block returns a truthy value, the element to be found + # is itself or lies in front. + # + # Returns `nil` if the block didn't return a truthy value for any element. # # ``` # (0..10).bsearch { |x| x >= 5 } # => 5 # (0..Float64::INFINITY).bsearch { |x| x ** 4 >= 256 } # => 4 # ``` - # - # Returns `nil` if the block didn't return `true` for any value. - def bsearch(&block : B | E -> Bool) + def bsearch(&block : B | E -> _) from = self.begin to = self.end