[英]Why Ruby .map doesn't work with if statement
I'm getting an unexpected result with using if
inside .map
: 我在.map
使用if
获得了意外的结果:
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]
我预期: [11,12,13,13,14]
...but I'm instead getting: [nil, nil, nil, nil, 14]
...但是我却得到: [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? 其次,我知道最后一个表达式是方法的返回值那么if语句是否正确? The last expression is the return value of if statement. 最后一个表达式是if语句的返回值。
Thanks! 谢谢!
For elements that are < 4, item + 10 if item < 4
does indeed return the expected value. 对于小于4的元素, item + 10 if item < 4
确实返回期望值,则item + 10 if item < 4
。 But then the second statement executes, and map returns that value. 但是随后第二条语句执行,并且map返回该值。 For item < 4, item + 9 if item > 4
returns nil
. 对于项<4, item + 9 if item > 4
返回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? 如果项== 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
... 对于item=3
,第一行返回13
,但这不是方法返回的内容-该方法继续到下一行,其评估为nil
...
In order to return a single value according to several conditions, you can use if..elsif..else
construct, or a case..when
construct: 为了根据多个条件返回单个值,可以使用if..elsif..else
构造,或case..when
构造:
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. case..when
返回第一个 when
子句之后的块,该子句的值为true。
It's because if you use map
, you create array containing values evaluated from block passed into map
method. 这是因为,如果使用map
,则会创建一个数组,其中包含从传递给map
方法的块中求值的值。 So in this case, the last value evaluated in first 4 elements is item + 9 if item > 4
, which returns nil
. 因此,在这种情况下, item + 9 if item > 4
, item + 9 if item > 4
在前4个元素中求值的最后一个值为item + 9 if item > 4
,它返回nil
。
Ruby 2.7+ Ruby 2.7以上
There be a solution now! 现在有解决方案!
Ruby 2.7 is introducing filter_map
for this exact purpose. Ruby 2.7为此引入了filter_map
。 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! 希望对某人有用!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.