如果符合某个条件,我会尝试累积一些值。 为什么这个片段返回nil,当我希望它返回2?
[[1, 2], [2, 3], [3, 8], [4, 2]].inject(0) { |s, e| s + e[1] if e[0] <= 1}
inject
不是正确的方法吗?
答案 0 :(得分:6)
你应该返回s;
[[1, 2], [2, 3], [3, 8], [4, 2]].inject(0) { |s, e| s += e[1] if e[0] <= 1; s}
小清洁
[[1, 2], [2, 3], [3, 8], [4, 2]].inject(0){|s,(k,v)| s += (k<2 ? v : 0)}
答案 1 :(得分:3)
你可以分多步完成:
>> a = [[1, 2], [2, 3], [3, 8], [4, 2]]
>> a.select { |e| e.first <= 1 }.inject(0) { |s, e| s += e.last }
=> 2
>> a.select { |e| e.first <= 1 }.map(&:last).inject(0, :+)
=> 2
使用单个inject
完成所有操作应该更有效率,但将其分解为碎片可能更清晰,除非您拥有非常大的阵列,否则速度差异不会明显。
如果您不介意使用哈希或数组模拟指针,可以使用each_with_object
执行此操作:
>> a.each_with_object({ :sum => 0 }) { |(k,v), m| m[:sum] += v if k <= 1 }[:sum]
=> 2
>> a.each_with_object([0]) { |(k,v), m| m[0] += v if k <= 1 }.first
=> 2
inject
块的结果将在下次调用您的块时用作s
的值。在第二个迭代器上,这个:
s + e[1] if e[0] <= 1
的值为nil
,因为e[0]
将为2.后续迭代也会从您的块中返回nil
,因为除了第一个e[0]
之外,每个s
都大于1 。这就是您需要从块中返回[[1, 2], [2, 3], [3, 8], [4, 2], [1, 11]]
的原因。如果你有这样的数组:
nil
那么你甚至不会从inject
中获得NoMethodError: undefined method `+' for nil:NilClass
,你只能例外:
nil
当您的区块尝试将11添加到{{1}}时。
答案 2 :(得分:2)
另一种方式:
xs.map { |k, v| v if k <= 1 }.compact.inject(0, :+)
请注意Ruby如何从缺乏列表推导中受到影响,我们必须(有些低效率)使用map + compact
来模拟它。在使用LC的语言中,它看起来更好:sum(v for (k, v) in xs if k <= 1)
。