I'm getting an unexpected result with using if
inside .map
:
a = [1,2,3,4,5]
a.map do |item|
item + 10 if item < 4
item + 9 if item > 4
end
I expected: [11,12,13,13,14]
...but I'm instead getting: [nil, nil, nil, nil, 14]
Why's that?
Secondly, I know that the last expression is the return value of method So does this true with if statement? The last expression is the return value of if statement.
Thanks!
For elements that are < 4, item + 10 if item < 4
does indeed return the expected value. But then the second statement executes, and map returns that value. For item < 4, item + 9 if item > 4
returns nil
.
Your map should look like this instead:
a.map do |item|
if item < 4 then
item + 10
else
item + 9
end
end
What do you do if item == 4?
We can demonstrate the problem you have by writing the block as a method:
def test_map(item)
item + 10 if item < 4
item + 9 if item > 4
end
test_map 3
# => nil
test_map 5
# => 14
What happens here? For item=3
the first line returns 13
, but that's not what's returned from the method - the method continues to the next line, which is evaluated to nil
...
In order to return a single value according to several conditions, you can use if..elsif..else
construct, or a case..when
construct:
def test_map2(item)
case item
when 0..4
item + 10
when 4..10
item + 9
else
item
end
end
test_map2 3
# => 13
test_map2 5
# => 14
case..when
returns the block after the first when
clause which is evaluated to true.
It's because if you use map
, you create array containing values evaluated from block passed into map
method. So in this case, the last value evaluated in first 4 elements is item + 9 if item > 4
, which returns nil
.
Ruby 2.7+
There be a solution now!
Ruby 2.7 is introducing filter_map
for this exact purpose. It's idiomatic and performant, and I'd expect it to become the norm very soon.
For example:
numbers = [1, 2, 5, 8, 10, 13]
enum.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]
Here's a good read on the subject .
Hope that's useful to someone!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.