为什么Ruby .map不能使用if语句

时间:2014-07-24 09:17:15

标签: ruby arrays

我在if内使用.map时收到了意外的结果:

a = [1,2,3,4,5]
a.map do |item|
  item + 10 if item < 4
  item + 9  if item > 4
end

我期待:[11,12,13,13,14]
......但我得到了:[nil, nil, nil, nil, 14]

为什么?

其次,我知道最后一个表达式是方法的返回值 if语句也是如此吗?最后一个表达式是if语句的返回值。

谢谢!

4 个答案:

答案 0 :(得分:1)

对于&lt; 4,item + 10 if item < 4确实返回了预期值。但随后第二个语句执行,map返回那个值。对于项目&lt; 4,item + 9 if item > 4返回nil

您的地图应该是这样的:

a.map do |item|
  if item < 4 then
      item + 10
  else
      item + 9
  end
end

如果项目== 4,你会怎么做?

答案 1 :(得分:1)

我们可以通过将块写为方法来证明您遇到的问题:

def test_map(item)
  item + 10 if item < 4
  item + 9  if item > 4
end

test_map 3
# => nil
test_map 5
# => 14

这里发生了什么?对于item=3,第一行返回13,但这不是从方法返回的内容 - 该方法继续到下一行,评估为nil ...

为了根据多个条件返回单个值,您可以使用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返回第一个 when子句之后的块,该子句被评估为true。

答案 2 :(得分:1)

Ruby 2.7 +

现在有解决方案!

Ruby 2.7为此引入了filter_map。它是惯用语言和高性能,我希望它很快会成为常态。

例如:

numbers = [1, 2, 5, 8, 10, 13]
enum.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]

这里是good read on the subject

希望对某人有用!

答案 3 :(得分:0)

这是因为如果您使用map,则创建包含从传递到map方法的块计算的值的数组。因此,在这种情况下,前4个元素中评估的最后一个值是item + 9 if item > 4,它返回nil