Determining if a variable is within range?

RubyIntegerConditionalRange

Ruby Problem Overview


I need to write a loop that does something like:

if i (1..10)
  do thing 1
elsif i (11..20)
  do thing 2
elsif i (21..30)
  do thing 3
etc...

But so far have gone down the wrong paths in terms of syntax.

Ruby Solutions


Solution 1 - Ruby

if i.between?(1, 10)
do thing 1
elsif i.between?(11,20)
do thing 2
...

Solution 2 - Ruby

Use the === operator (or its synonym include?)

if (1..10) === i

Solution 3 - Ruby

As @Baldu said, use the === operator or use case/when which internally uses === :

case i
when 1..10
  # do thing 1
when 11..20
  # do thing 2
when 21..30
  # do thing 3
etc...

Solution 4 - Ruby

if you still wanted to use ranges...

def foo(x)
 if (1..10).include?(x)
   puts "1 to 10"
 elsif (11..20).include?(x)
   puts "11 to 20"
 end
end

Solution 5 - Ruby

You could use

elsif (11..20).cover? i then thing_2

and according to this benchmark in Fast Ruby is faster than include?

Solution 6 - Ruby

You can usually get a lot better performance with something like:

if i >= 21
  # do thing 3
elsif i >= 11
  # do thing 2
elsif i >= 1
  # do thing 1

Solution 7 - Ruby

Not a direct answer to the question, but if you want the opposite to "within":

(2..5).exclude?(7)

>true

Solution 8 - Ruby

If you need the fastest way to do it, use the good old comparing.

require 'benchmark'

i = 5
puts Benchmark.measure { 10000000.times {(1..10).include?(i)} }
puts Benchmark.measure { 10000000.times {i.between?(1, 10)}   }
puts Benchmark.measure { 10000000.times {1 <= i && i <= 10}   }

on my system prints:

0.959171   0.000728   0.959899 (  0.960447)
0.919812   0.001003   0.920815 (  0.921089)
0.340307   0.000000   0.340307 (  0.340358)

As you can see, double comparing is almost 3 times faster than #include? or #between? methods!

Solution 9 - Ruby

A more dynamic answer, which can be built in Ruby:

def select_f_from(collection, point) 
  collection.each do |cutoff, f|
    if point <= cutoff
      return f
    end
  end
  return nil
end

def foo(x)
  collection = [ [ 0, nil ],
                 [ 10, lambda { puts "doing thing 1"} ],
                 [ 20, lambda { puts "doing thing 2"} ],
                 [ 30, lambda { puts "doing thing 3"} ],
                 [ 40, nil ] ]

  f = select_f_from(collection, x)
  f.call if f
end

So, in this case, the "ranges" are really just fenced in with nils in order to catch the boundary conditions.

Solution 10 - Ruby

For Strings:

(["GRACE", "WEEKLY", "DAILY5"]).include?("GRACE")

#=>true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbtwView Question on Stackoverflow
Solution 1 - RubyrogerdpackView Answer on Stackoverflow
Solution 2 - RubyBalduView Answer on Stackoverflow
Solution 3 - RubyVincent RobertView Answer on Stackoverflow
Solution 4 - RubyTim HoolihanView Answer on Stackoverflow
Solution 5 - RubyJuan Felipe RodriguezView Answer on Stackoverflow
Solution 6 - RubyBrad WerthView Answer on Stackoverflow
Solution 7 - RubyFellow StrangerView Answer on Stackoverflow
Solution 8 - RubyIvan OlshanskyView Answer on Stackoverflow
Solution 9 - Rubym104View Answer on Stackoverflow
Solution 10 - Rubyvidur punjView Answer on Stackoverflow