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.
It isn't very DRY:
has_matched? = true
is littered all over the place.You always need to remember to place
var
on the right-hand-side of===
, because that's whatcase
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
Test | Chrome | Firefox | Opera | Edge | Brave | Node |
---|---|---|---|---|---|---|
1.0 time | 15 ms | 14 ms | 17 ms | 17 ms | 16 ms | 14 ms |
if-immediate | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
if-indirect | 2.20 | 1.21 | 2.06 | 2.18 | 2.19 | 1.93 |
switch-immediate | 2.07 | 1.43 | 1.71 | 1.71 | 2.19 | 1.93 |
switch-range | 3.60 | 2.00 | 2.47 | 2.65 | 2.88 | 2.86 |
switch-range2 | 2.07 | 1.36 | 1.82 | 1.71 | 1.94 | 1.79 |
switch-indirect-array | 2.93 | 1.57 | 2.53 | 2.47 | 2.75 | 2.50 |
array-linear-switch | 2.73 | 3.29 | 2.12 | 2.12 | 2.38 | 2.50 |
array-binary-switch | 5.80 | 6.07 | 5.24 | 5.24 | 5.44 | 5.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
How to Update a Single Attribute Without Touching the Updated_At Attribute
How to Install Ruby 1.9.3 on Ubuntu Without Rvm
How to Specify "Http Request Header" in Openuri
How to Sort by Multiple Conditions with Different Orders
How to Add Child Nodes in Nodeset Using Nokogiri
Removing Child Root Nodes in Rabl
Firebase Token Error, "The Custom Token Corresponds to a Different Audience."
Learning Ruby: Recommended Blogs to Read
What Are the Conventional Gem Paths for Ruby Under Os X 10.5
How to View a Sample of the Call Stack in Ruby
Select Mailbox "Sent Mail" or "All Mail" in Ruby Net::Imap
Are There Better Ways to Prevent 'Yield' When No Block Is Passed In
Ruby Equivalent of Perl Data::Dumper
Best Way to Group by Date with Mongoid
Deleting While Iterating in Ruby
What's the Fastest Way to Check If a Word from One String Is in Another String