39

I am looking for a built-in Ruby method that has the same functionality as index but uses a binary search algorithm, and thus requires a pre-sorted array.

I know I could write my own implementation, but according to "Ruby#index Method VS Binary Search", the built-in simple iterative search used by index is faster than a pure-Ruby version of binary search, since the built-in method is written in C.

Does Ruby provide any built-in methods that do binary search?

Community
  • 1
  • 1
Jonah
  • 15,806
  • 22
  • 87
  • 161
  • No need to write your own: [tyler/binary_search](https://github.com/tyler/binary_search). The author has also taken the time to run some benchmarks. – sczizzo Dec 29 '11 at 19:33
  • Hi sczizzo, I am new to ruby so this is a pretty newb question, but how do I add this functionality to my ruby installation? Is it just a matter of running the rakefile? Thanks. – Jonah Dec 29 '11 at 19:53
  • 2
    Might be easier to use the `bsearch` gem, as Marc-André suggested. Then it's pretty much as simple as `gem install bsearch` on the command line, and `require 'bsearch'` in your Ruby. You might want to [look at the documentation for usage](http://rubydoc.info/gems/bsearch/1.5.0/frames). – sczizzo Dec 29 '11 at 20:15
  • 4
    It should be noted that even if it is written in ruby any implementation of a binary search will eventually outperform any implementation of linear search, no matter how optimized, for large enough arrays. – sepp2k Dec 29 '11 at 20:31

3 Answers3

62

Ruby 2.0 introduced Array#bsearch and Range#bsearch.

For Ruby 1.9, you should look into the bsearch and binary_search gems. Other possibility is to use a different collection than an array, like using rbtree

bsearch is in my backports gem, but this is a pure Ruby version, so quite a bit slower. Note that a pure Ruby binary search will still be faster than a linear builtin search like index or include? for big enough arrays/ranges (or expensive comparisons), since it's not the same order of complexity O(log n) vs O(n).

To play with it today, you can require 'backports/2.0.0/array/bsearch' or require 'backports/2.0.0/range/bsearch'.

Good luck!

Dennis
  • 56,821
  • 26
  • 143
  • 139
Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
12

A lot has changed since 2011, in Ruby 2.3, you can use bsearch_index

https://ruby-doc.org/core-2.3.0/Array.html#method-i-bsearch_index

array.bsearch_index { |val| query <=> val }

Yoav Epstein
  • 849
  • 9
  • 7
3

I use bsearch. This is how it works:

array = ['one', 'two', 'three', 'four', 'five']

search = array.sort.bsearch { |value| 'four' <=> value }

Note: binary search needs a sorted array; this adds a li'l overhead but it's fine, compared to the speed of the search.

search will return the value four of the array, else nil if it doesn't find the value.

Kaka Ruto
  • 4,581
  • 1
  • 31
  • 39