How to Use Ruby " Case ... When " with Inequalities

how to use ruby case ... when with inequalities?

You are mixing two different types of case statements:

case var
when 1
dosomething
when 2..3
doSomethingElse
end

case
when var == 1
doSomething
when var < 12
doSomethingElse
end

Implementing the 'case' statement in order to match multiple 'when' conditions

Ruby doesn't have any sort of fall-through for case.

One alternative be a series of if statements using the === method, which is what case uses internally to compare the items.

has_matched? = false

if '2' === var
has_matched? = true
# stuff
end

if '3' === var
has_matched? = true
# other stuff
end

if something_else === var
has_matched? = true
# presumably some even more exciting stuff
end

if !has_matched?
# more stuff
end

This has two glaring issues.

  1. It isn't very DRY: has_matched? = true is littered all over the place.

  2. You always need to remember to place var on the right-hand-side of ===, because that's what case does behind the scenes.

You could create your own class with a matches? method that encapsulates this functionality. It could have a constructor that takes the value you'll be matching against (in this case, var), and it could have an else_do method that only executes its block if its internal @has_matched? instance variable is still false.

Edit:

The === method can mean anything you want it to mean. Generally, it's a more "forgiving" way to test equivalency between two objects. Here's an example from this this page:

class String
def ===(other_str)
self.strip[0, other_str.length].downcase == other_str.downcase
end
end

class Array
def ===(str)
self.any? {|elem| elem.include?(str)}
end
end

class Fixnum
def ===(str)
self == str.to_i
end
end

Essentially, when Ruby encounters case var, it will call === on the objects against which you are comparing var.

Multiple Inequalities in Ruby

Maybe unless [1,4,7].include?($my_variable[1]) will do the trick?

Inequalities inside a switch statement

It is actually possible, if you do it like this. The case whose expression evaluates to true is executed.

var a = +prompt("Please input a number.");

switch (true) {
case (a<1): alert("less than 1");
break;
case (a<2): alert("less than 2");
break;
case (a<3): alert("less than 3");
break;
default: alert("greater than or equal to 3");
}

Note: Personally I feel you should use if-else for this purpose.

Is there a way to know which 'when' value was correct in a multiple case choice in Ruby

Maybe I'm oversimplifying here, but I would think you could do this:

case x
when 0
puts "You shall not pass!"
do_stuff
when 1..10
puts x
do_other_stuff(x)
end

ruby: how avoid if-then-else when doing case-insensitive comparison that handles nil too

@showdate = params[:showdate].to_s.downcase == "true"

Working with arbitrary inequalities and checking which, if any, are satisfied

class RuleSet
Rule = Struct.new(:op1,:op,:op2,:result) do
def <=>(r2)
# Op of "=" sorts before others
[op=="=" ? 0 : 1, op2.to_i] <=> [r2.op=="=" ? 0 : 1, r2.op2.to_i]
end
def matches(n)
@op2i ||= op2.to_i
case op
when "=" then n == @op2i
when "<" then n < @op2i
when ">" then n > @op2i
end
end
end

def initialize(text)
@rules = text.each_line.map do |line|
Rule.new *line.split(/[\s:]+/)
end.sort
end

def value_for( n )
if rule = @rules.find{ |r| r.matches(n) }
rule.result=="n" ? n : rule.result.to_i
end
end
end

set = RuleSet.new( DATA.read )
-1.upto(8) do |n|
puts "%2i => %s" % [ n, set.value_for(n).inspect ]
end

#=> -1 => 5
#=> 0 => 1
#=> 1 => 5
#=> 2 => 5
#=> 3 => 5
#=> 4 => 5
#=> 5 => 10
#=> 6 => nil
#=> 7 => 7
#=> 8 => nil

__END__
n = 0: 1
n < 5: 5
n = 5: 10
n = 7: n

Switch statement for greater-than/less-than

When I looked at the solutions in the other answers I saw some things that I know are bad for performance. I was going to put them in a comment but I thought it was better to benchmark it and share the results. You can test it yourself. Below are my results (ymmv) normalized after the fastest operation in each browser.

Here is the results from 2021-MAY-05

































































































TestChromeFirefoxOperaEdgeBraveNode
1.0 time15 ms14 ms17 ms17 ms16 ms14 ms
if-immediate1.001.001.001.001.001.00
if-indirect2.201.212.062.182.191.93
switch-immediate2.071.431.711.712.191.93
switch-range3.602.002.472.652.882.86
switch-range22.071.361.821.711.941.79
switch-indirect-array2.931.572.532.472.752.50
array-linear-switch2.733.292.122.122.382.50
array-binary-switch5.806.075.245.245.445.37

Ruby: Any consequences with using multiple return..if statements?

This is an extended comment. No upvotes, please (downvotes OK).

I would be inclined to write this as follows.

def triangle(side1, side2, side3) 
if valid_triangle?(side1, side2, side3)
triangle_type(side1, side2, side3)
else
:invalid
end
end

def triangle_type(*sides)
case nbr_equal_sides(sides)
when 3
:equilateral
when 2
:isosceles
else
:scalene
end
end

def valid_triangle?(*sides)
sides.sum > 2 * sides.max
end

def nbr_equal_sides(sides)
4 - sides.uniq.size
end

Line segments of lengths n1, n2, n3 can form a triangle if and only if the following three inequalities hold:

n1 + n2 > n3
n1 + n3 > n2
n2 + n3 > n1

which can be written:

tot > 2 * n3
tot > 2 * n2
tot > 2 * n1

where

tot = n1 + n2 + n3

which is the same as:

tot > 2 * [n1,n2,n3].max

Those not philosophically opposed to early returns could use a guard clause in triangle:

def triangle(side1, side2, side3) 
return :invalid unless valid_triangle?(side1, side2, side3)
triangle_type(side1, side2, side3)
end

The Ruby Style Guide (search "guard clause") and Robocop advocate the use of guard clauses.



Related Topics



Leave a reply



Submit