61

I want to test whether a equals 1 or 2

I could do

a == 1 || a == 2

but this requires repeating a (which would be annoying for longer variables)

I'd like to do something like a == (1 || 2), but obviously this won't work

I could do [1, 2].include?(a), which is not bad, but strikes me as a bit harder to read

Just wondering how do to this with idiomatic ruby

Tom Lehman
  • 85,973
  • 71
  • 200
  • 272
  • Ha, I was -just- messing around with this in PHP looking for an answer. For me it was [ if (Monday, T, or W) elseif (Th, F) else ...] It was a tossup between the "ugly" method you noted, and a switch/case chain. What I wanted though was the same construct you noted [if a == (M || T || W)] – Alex Mcp Feb 04 '10 at 00:05
  • 5
    @danben - I'm not sure how to interpret your comment. Maybe you mean "the code is already so easy to read that this doesn't matter; you should see the crap I had to do in [other language]." If so, I'd respond that 1) if I ever maintain the OP's code, I'll appreciate all efforts at readability, and 2) presumably the average Ruby program is doing larger tasks than the average C program, so the total complexity is about constant. You don't think programmers are dumber these days, do you? If not, they probably have enough work to keep them busy, just like programmers of yore did. – Nathan Long Jun 07 '12 at 18:33

8 Answers8

39

Your first method is idiomatic Ruby. Unfortunately Ruby doesn't have an equivalent of Python's a in [1,2], which I think would be nicer. Your [1,2].include? a is the nearest alternative, and I think it's a little backwards from the most natural way.

Of course, if you use this a lot, you could do this:

class Object
  def member_of? container
    container.include? self
  end
end

and then you can do a.member_of? [1, 2].

Peter
  • 127,331
  • 53
  • 180
  • 211
  • 3
    Why not to rename `member_of?` to `in?`? – ib. Feb 04 '10 at 05:52
  • Random question. But the language is constantly being worked on, so why aren't commonly used methods (like the one you defined above) included by default? Is it to stop the language being too large and unwieldy? Coming from Python, it seems odd that a language wouldn't have such a simple and useful method – stevec Jan 31 '19 at 13:13
12

I don't know in what context you're using this in, but if it fits into a switch statement you can do:

a = 1
case a
when 1, 2
  puts a
end

Some other benefits is that when uses the case equality === operator, so if you want, you can override that method for different behavior. Another, is that you can also use ranges with it too if that meets your use case:

when 1..5, 7, 10
Jack Chu
  • 6,791
  • 4
  • 38
  • 44
10

One way would be to petition "Matz" to add this functionality to the Ruby specification.

if input == ("quit","exit","close","cancel") then
  #quit the program
end

But the case-when statement already lets you do exactly that:

case input when "quit","exit","close","cancel" then 
  #quit the program
end

When written on one line like that, it acts and almost looks like an if statement. Is the bottom example a good temporary substitution for the top example? You be the judge.

Arcolye
  • 6,968
  • 4
  • 34
  • 28
  • 3
    Personally I don't like the idea of using `if input == ("quit", "exit"...)` as it messes badly with testing for array equality. The use of `case ... when ...` is nicer because it is valid syntax, though it's a bit unexpected. I think the use of an "in" operator to test for inclusion in an array, as mentioned in other responses, would be a good addition to the language. – the Tin Man Aug 30 '10 at 15:41
7

First put this somewhere:

class Either < Array
  def ==(other)
    self.include? other
  end
end

def either(*these)
  Either[*these]
end

Then, then:

if (either 1, 2) == a
  puts "(i'm just having fun)"
end
Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
  • This is remarkably similar to the syntax for Perl 6's `any` and `all` junctions. Is there an easy way to allow `a == (either 1, 2)` as well? – Chris Lutz Feb 04 '10 at 01:21
  • @Chris Lutz: Not in the general case. As you can see from the method implementation, the `==` operator is just semantic sugar for calling the `==` method of the object on its left-hand side. – Chuck Feb 04 '10 at 01:33
5

You can just use intersection like

([a] & [1,2]).present?

a alternative way.

Gourav
  • 570
  • 3
  • 16
3

Include is definitely the way to go here.

  %w[cat dog].include?(type)
esbanarango
  • 1,634
  • 15
  • 17
2
a.to_s()=~/^(1|2)$/
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 6
    gross or not, its up to individual. To me, going the extra mile of creating custom classes, doing fancy things, is gross. – ghostdog74 Feb 04 '10 at 02:18
  • 2
    Setting up a regex-evaluating finite state machine and converting a number into a string just to test equality is far more extravagant and "fancy" than Jeremy's `either` method. – Chuck Feb 06 '10 at 00:27
  • to each his own. It takes just 1 line to test the numbers and I am super fine with that! – ghostdog74 Feb 06 '10 at 01:06
  • @ghostdog74 - one line, eh? Would you prefer `class Object;def in?(c);c.include?(self);end;end;`? :) I'm teasing, but I do think that in a language where even `false` is an object and `Class` is a class, creating a class isn't "fancy." – Nathan Long Jun 07 '12 at 18:40
-1

Maybe I'm being thick here, but it seems to me that:

(1..2) === a

...works.

Shadowfirebird
  • 757
  • 3
  • 13