简体   繁体   English

为什么Ruby .map无法与if语句一起使用

[英]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 > 4item + 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM