1

I had to use something like

arr = [10, 20, 50, 80, 110]
(arr.bsearch_index{|a| a >= 50} || arr.length) - 1      # => 1
(arr.bsearch_index{|a| a >= 2000} || arr.length) - 1    # => 4

with the return value -1 meaning there is no such index. What if the numbers could be float, so you cannot look for 49 instead when n is 50. The code right now is a little bit messy. Is there a more elegant way to do it?

(Maybe it is just how bsearch_index() does it: to return nil when not found... so we just have to use bsearch(){ } || arr.length to convert it back to strictly numbers -- so that's just the way it is. bsearch_index has to either return only numbers or it can return nil as a design decision and it chose to return nil. But I am not sure if we just have to use the code above. Maybe the find-any mode of bsearch_index or some kind of way can do it and is more elegant.)

P.S. it might be interesting to use a reverse() operation or negating every element or something, but since those are O(n), it defeats the purpose of using a O(lg n) solution using binary search and we can just do a linear search.

nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 1
    _"the first index in array so that [...]"_ – `1` is the index of the _last_ element smaller than 50, not the _first_ one. That would be `0`, i.e. 10. – Stefan Aug 30 '19 at 11:36
  • @Stefan I see what you mean. The original question "look for the first index in array" actually was trying to mean the first one next to where 50 would be"... so I changed it. It is either "the rightmost" or the "closest" index – nonopolarity Aug 30 '19 at 12:29

2 Answers2

1

In order to express "less than" directly (i.e. via <), you have to reverse the array:

rindex = arr.reverse.bsearch_index { |a| a < 50 }
#=> 4

To un-reverse the index:

arr.size - rindex - 1
#=> 1

In one line:

arr.reverse.bsearch_index { |a| a < 50 }.yield_self { |i| arr.size - i - 1 if i }

The the modifier-if handles i being nil, e.g. a < 10


Or simply use a descending array in the first place:

arr = [110, 80, 50, 20, 10]
arr.bsearch_index { |a| a < 50 }   #=> 3
arr.bsearch_index { |a| a < 2000 } #=> 0
Stefan
  • 109,145
  • 14
  • 143
  • 218
0

Not completely clear, but for a sorted Array I guess:

arr.bsearch_index{ |a| a >= n }.then { |i| i ? i - 1 : -1}

Or, since nil.to_i #=> 0

arr.bsearch_index{ |a| a >= n }.to_i - 1

# n = 49 #=> 1
# n = 50 #=> 1
# n = 51 #=> 2
# n = 111 #=> -1
iGian
  • 11,023
  • 3
  • 21
  • 36