Reputation: 563
At first I thought this syntax worked but it seems when
will only check the first value of the groups, if any of the first values fail it will return locked. to bad the or
operand doesn't work here.
def lock(a,b,c,d)
case [a,b,c,d]
when[(3||5||7), 2, (5||6), (8||9||0)]
"unlocked"
else
"locked"
end
end
lock(3, 2, 5, 8)
lock(5, 2, 5, 0)
lock(5, 2, 6, 8)
lock(7, 2, 5, 8)
lock(7, 2, 6, 9)
I could do an if else statement for each variable, but i was hoping there was a way to do a case statement without having to make multiple when statements.
Upvotes: 1
Views: 1487
Reputation: 110685
As has been explained by others, this problem does not lend itself to the use of a case statement.
Since the variables appear to be digits, you could convert them to strings and use a regular expression.
def lock(entry, valid)
r = /#{valid.map { |a| '['+a.join('|')+']' }.join }/
entry.join.match?(r) ? 'unlocked' : 'locked'
end
Suppose
valid = [[3, 5, 7], [2], [5, 6], [8, 9, 0]]
We compute the following regular expression for this value of valid
:
r #=> /[3|5|7][2][5|6][8|9|0]/
Try it:
lock([3, 2, 5, 8], valid) #=> "unlocked"
lock([5, 2, 5, 0], valid) #=> "unlocked"
lock([5, 2, 6, 8], valid #=> "unlocked"
lock([7, 2, 5, 8], valid) #=> "unlocked"
lock([7, 2, 6, 9], valid) #=> "unlocked"
lock([5, 2, 4, 0], valid) #=> "locked"
Upvotes: 0
Reputation: 10497
I'll opt to loop the array instead of using a case
statement, like this:
def lock(a,b,c,d)
combination = [[3,5,7], [2], [5,6], [8,9,0]]
attempt = [a,b,c,d]
combination.each_with_index do |position, i|
return "locked" unless position.include?(attempt[i])
end
"unlocked"
end
Outputs:
lock(3, 2, 5, 8)
#=> "unlocked"
lock(5, 2, 5, 0)
#=> "unlocked"
lock(5, 2, 6, 8)
#=> "unlocked"
lock(7, 2, 5, 8)
#=> "unlocked"
lock(7, 2, 6, 9)
#=> "unlocked"
lock(1, 2, 3, 4)
#=> "locked"
Why your solution fails?
Just as Hamms pointed out in his comment, the when
with [(3||5||7), 2, (5||6), (8||9||0)]
evaluates to [3, 2, 5, 8]
. That is because each expression in parenthesis is evaluated first, so, breaking it down, it would be:
(3 || 5 || 7)
#=> 3
2
#=> 2
(5 || 6)
#=> 5
(8 || 9 || 0)
#=> 8
This is because ||
is evaluating if value is truthy, that is, is neither nil
nor false
. As soon as the expression gets to a truthy value, it will return that value and look no further. So any number will evaluate as truthy, and you will always get the first number of each expression as a result.
Back to your case
statement, it is the exact same thing as writing it like:
case [a,b,c,d]
when [3, 2, 5, 8]
"unlocked"
else
"locked"
end
Now consider that a case
statement will evaluate if the object in case
is equal with the one in each when
. So in, your case will be something like:
[a,b,c,d] === [3, 2, 5, 8]
Which will return true
(and "unlocked"
) only when you call lock(3, 2, 5, 8)
.
Also consider that you could use multiple values with when
, so using something like this will work:
case [a,b,c,d]
when [3, 2, 5, 8], [5, 2, 5, 0] then "unlocked"
else "locked"
end
In which when
will be equivalent to doing:
[a,b,c,d] === [3, 2, 5, 8] || [5, 2, 5, 0]
Upvotes: 2