Ruby 2.0.0 Array # bsearch поведение

Я заметил, что с Ruby 2.0.0 класс массива имеет метод bsearch, который я тестировал, и я не получаю такого поведения, которого я ожидал бы. Почему он возвращает значение для 2 и 5, но nil для -1, 1 и 4?

arr_in = [-1, 1, 2, 4, 5]

arr_in.bsearch { |x| x == 3 }   #=> nil
arr_in.bsearch { |x| x == -1 }  #=> nil
arr_in.bsearch { |x| x == 1 }   #=> nil
arr_in.bsearch { |x| x == 2 }   #=> 2
arr_in.bsearch { |x| x == 4 }   #=> nil
arr_in.bsearch { |x| x == 5 }   #=> 5

Ответы

Ответ 1

arr_in = [-1, 1,2,4,5]
arr_in.bsearch{ |x| 2 - x }
#=> 2
arr_in.bsearch{ |x| -1 - x }
#=> -1
arr_in.bsearch{ |x| 3 - x }
#=> nil

Двоичный поиск использует результат блока как подсказку, какая часть массива (левая или правая сторона) должна быть выбрана для поиска на следующей итерации. Если блок возвращает 0, он прекратит поиск. Если он возвращает меньше 0, он будет идти влево, иначе он будет прав:)

Подробнее здесь http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-bsearch

UPD

Хорошо, возьмем ваш пример

arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 3 }

Сначала мы возьмем средний элемент (2) и передадим его блоку. 2 == 3 вернет false, поэтому мы перейдем к правой части массива.

Возьмем средний элемент [4, 5], который 5 и 5 == 3 равен false

Нет никаких элементов справа, поэтому мы вернем nil

arr_in = [-1, 1, 2, 4, 5]
arr_in.bsearch { |x| x == 2 }

Первый 2 == 2 - true. Мы идем влево.

Средний элемент [-1, 1] равен 1. 1 == 2 is false. Мы идем направо.

В [-1, 1] нет никаких элементов справа от 1, поэтому мы возвращаем последний последний элемент, который возвращает оператор true, который равен 2

PS: не забывайте, что массив должен быть отсортирован;)

Ответ 2

Я считаю более интуитивным использование оператора космического корабля

array.bsearch {|x| 3 <=> x }

Просто поставьте x справа от космического корабля.

Это также работает для строк и любого объекта, сравнимого с <=>.