What is the most succinct way to use Ruby's equal (==) and or (||) operators together in an if statement?

Viewed 82

I have an if statement in Ruby that combines the == and || operators, and it's quite verbose. What would be a more succinct way to write this:

if number == "1.0" || number == "2.0" || number == "3.0" || number == "4.0" || number == "5.0"
  hierarchy = "Chapter"
end
3 Answers
hierarchy = "Chapter" if ["1.0", "2.0", "3.0", "4.0", "5.0"].include?(number)

or as @Stefan commented you can use percent literals

hierarchy = "Chapter" if %w[1.0 2.0 3.0 4.0 5.0].include?(number)

To answer the actual question: there is no succinct way to combine these 2 operations without constructing another object.

For example: Array and Enumerable#any? are very similar to what you are doing

chapters = ["1.0","2.0","3.0","4.0","5.0"]
chapters.any? {|n| n == number} 

This is essentially: chapters[0] == number || chapters[1] == number #...

However

Assuming your formatting is "chapter.subchapter" where chapter is a number and subchapter == "0" indicates "Chapter".

I would go with the following as it would be independent of the "number" of Chapters

hierarchy = "Chapter" if number.match?(/\A\d+\.0\z/)

This compares number with the Regexp, which in words is "String starts with one or more numbers followed by a period followed by 0 and the end of the String".

e.g.

def chapter_hierarchy(number) 
  "Chapter" if number.match?(/\A\d+\.0\z/)
end 

["1.0","1.1","2.0","2.01","3.0", "47.0010", "52.0", "A.0"].map {|n| [n,chapter_hierarchy(n)] }
#=> [["1.0", "Chapter"], 
#    ["1.1", nil], 
#    ["2.0", "Chapter"], 
#    ["2.01", nil], 
#    ["3.0", "Chapter"], 
#    ["47.0010", nil], 
#    ["52.0", "Chapter"]
#    ["A.0", nil]]

The simplest way is to just leverage Ruby's very capable case statement:

case number 
when "1.0", "2.0", "3.0", "4.0", "5.0"
  hierarchy = "Chapter"
end

If any of those match, as compared with #===, then that branch is followed.

You can also do this with a regular expression because the pattern is very simple:

if number.match?(/\A[12345]\.0\z/)
  # ...
end

If the patterns get non-trivial and there's a lot of entries and you're doing a lot of tests, the fastest way to match is often using Set, which does very quick inclusion tests:

CHAPTERS = Set.new(%w[ 1.0 2.0 3.0 4.0 5.0 ])

if CHAPTERS.include?(number)
  # ...
end
Related