Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

If I have a value 'Dog' and an array ['Cat', 'Dog', 'Bird'], how do I check this w/o looping through. Is there a simple way of checking if the value exists, nothing more?

share|improve this question

7 Answers

up vote 304 down vote accepted

You're looking for include?:

>> ['Cat', 'Dog', 'Bird'].include? 'Dog'
=> true
share|improve this answer
5  
Alternate syntax: %w(Cat Dog Bird).include? 'Dog' – scarver2 Dec 18 '12 at 22:04

Try

['Cat', 'Dog', 'Bird'].include?('Dog')
share|improve this answer

There is no in operator or #in? method, but it has been proposed before, in particular by Yusuke Endoh a top notch member of ruby-core.

As pointed out by others, the reverse method include? exists, for all Enumerables including Array, Hash, Set, Range:

['Cat', 'Dog', 'Bird'].include?('Unicorn') # => false

Note that if you have many values in your array, they will all be checked one after the other (i.e. O(n)), while that lookup for a hash will be constant time (i.e O(1)). So if you array is constant, for example, it is a good idea to use a Set instead. E.g:

require 'set'
ALLOWED_METHODS = Set[:to_s, :to_i, :upcase, :downcase
                       # etc
                     ]

def foo(what)
  raise "Not allowed" unless ALLOWED_METHODS.include?(what.to_sym)
  bar.send(what)
end

A quick test reveals that calling include? on a 10 element Set is about 3.5x faster than calling it on the equivalent Array (if the element is not found).

A final closing note: be wary when using include? on a Range, there are subtleties, so refer to the doc and compare with cover?...

share|improve this answer

Use Enumerable#include:

a.include? 'Dog'
share|improve this answer

If you want to check by a block, you could try any? or all?.

%w{ant bear cat}.any? {|word| word.length >= 3}   #=> true  
%w{ant bear cat}.any? {|word| word.length >= 4}   #=> true  
[ nil, true, 99 ].any?                            #=> true  

Details are here: http://ruby-doc.org/core-1.9.3/Enumerable.html
My inspiration come from here: http://stackoverflow.com/a/10342734/576497

share|improve this answer
Very useful if you want check any/all of those string is included in another string/constant – thanikkal Jul 12 '12 at 12:40

There's the other way around, too!

Suppose the array is [ :edit, :update, :create, :show ] - well perhaps the entire seven deadly/restful sins :)

And further toy with the idea of pulling a valid action from some string - say

my brother would like me to update his profile

Solution

[ :edit, :update, :create, :show ].select{|v| v if "my brother would like me to update his profile".downcase =~ /[,|.| |]#{v.to_s}[,|.| |]/}
share|improve this answer

Several answers suggest Array#include?, but there is one important caveat: Looking at the source, even Array#include? does perform looping:

rb_ary_includes(VALUE ary, VALUE item)
{
    long i;

    for (i=0; i<RARRAY_LEN(ary); i++) {
        if (rb_equal(RARRAY_AREF(ary, i), item)) {
            return Qtrue;
        }
    }
    return Qfalse;
}

The way to test the word presence without looping is by constructing a trie for your array. There are many trie implementations out there (google "ruby trie"). I will use rambling-trie in this example:

a = %w/cat dog bird/

require 'rambling-trie' # if necessary, gem install rambling-trie
trie = Rambling::Trie.create { |trie| a.each do |e| trie << e end }

And now we are ready to test the presence of various words in your array without looping over it, in O(log n) time, with same syntactic simplicity as Array#include?, using sublinear Trie#include?:

trie.include? 'bird' #=> true
trie.include? 'duck' #=> false
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.