Reputation: 643
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!
Upvotes: 0
Views: 9579
Reputation: 12203
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!
Upvotes: 2
Reputation: 37409
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.
Upvotes: 2
Reputation: 51161
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
.
Upvotes: 0
Reputation: 17132
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?
Upvotes: 2