What is the shortest / most idiomatic way to determine if a variable is any of one of the values?

This seems like a ridiculous simple question to ask, but what is the shortest / most idiomatic way to rewrite this in Ruby?

if variable == :a or variable == :b or variable == :c or variable == :d # etc. 

I saw this solution:

 if [:a, :b, :c, :d].include? variable 

but this is not always functionally equivalent. I suppose Array#include? really looks to see if the object contains a variable in the list; it does not take into account that an object can implement its own equality test with def ==(other) .

As helpful commentators note below, this explanation is incorrect. include? uses == but uses the == method of the elements in the array. In my example, these are characters, not the == method of a variable. This explains why this does not match my first code example.

(Take, for example, the Rails' Mime::Type : request.format == :html implementation may return true, but [:html].include?(request.format) will return false since request.format is an instance of Mime :: Type, not a symbol.)

The best I have so far:

 if [:a, :b, :c, :d].select {|f| variable == f}.any? 

but for me it seems a little cumbersome. Anyone have the best deals?

+7
syntax ruby
source share
5 answers

Actually, #include? uses == . The problem arises because if you do

 [:a].include? foo 

it checks :a == foo , not foo == :a . That is, it uses the == method defined for the objects in the array, and not for the variable. Therefore, you can use it until you make sure that the objects in the array have the correct == method.

In cases where this does not work, you can simplify your statement by deleting the select statement and passing the block directly to any :

 if [:a, :b, :c, :d].any? {|f| variable == f} 
+15
source share

Sounds like Array#include? uses == :

 >> class AString < String >> def ==(other) >> self[0] == other[0] >> end >> end >> asdf = AString.new "asdfg" => "asdfg" >> b = AString.new 'aer' => "aer" >> asdf == b => true >> [asdf].include? b => true 

Array#include? documentation Array#include? also explains this.

+3
source share

I always used your second example, if [:a, :b, :c, :d].include? variable if [:a, :b, :c, :d].include? variable . While this creates some problems with classes that overwrite == , it works great in most situations that I needed (usually checking for characters).

+1
source share

What about:

  if [:a, :b, :c, :d].index variable 
+1
source share

What you really do is see if the variable is a member of the set [:a,:b,:c,:d] so semantically that it maps to the include? method include? .

The problem you are facing is related to Ruby's typical nature of Ruby, so if you want to get around this, do not first convert to a symbol:

 if [:a, :b, :c, :d].include? variable.to_sym 
0
source share

All Articles