NeilS NeilS - 1 month ago 9
Ruby Question

What is the shortest/most idiomatic way of determining whether a variable is any one of a list of values?

This seems a ridiculously simple question to be asking, but what's the shortest/most idiomatic way of rewriting 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 isn't always functionally equivalent - I believe
Array#include?
actually looks to see if the variable object is contained in the list; it doesn't take into account that the object may implement its own equality test with
def ==(other)
.

As observed by helpful commentators below, that explanation isn't correct.
include?
does use
==
but it uses the
==
method of the items in the array. In my example, it's the symbols, rather than the
==
method of the variable. That explains why it's not equivalent to my first code example.

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

The best I have so far is:

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


but it seems somewhat cumbersome to me. Does anyone have better suggestions?

Answer

Actually, #include? does use ==. The problem arises from the fact that if you do

[:a].include? foo

it checks :a == foo, not foo == :a. That is, it uses the == method defined on the objects in the Array, not the variable. Therefore you can use it so long as you make sure the objects in the array have a proper == method.

In cases where that won't work, you can simplify your statement by removing the select statement and passing the block directly to any:

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