我对此代码的期望是数字3.为什么这不起作用?
mixed_array=[1,'cat',2]
mixed_array.inject(0) do |memo,num|
memo += num if num.is_a?Integer
end
NoMethodError: undefined method `+' for nil:NilClass
答案 0 :(得分:1)
你快到了那里:
mixed_array.inject(0) do |memo, num|
next memo unless num.is_a?(Integer)
memo + num
end
#=> 3
让代码正常工作:
mixed_array.inject(0) do |memo, num|
memo += num if num.is_a?(Integer)
memo # return memo on each iteration, because it becomes nil with non-integer element
end
#=> 3
答案 1 :(得分:0)
你所拥有的东西不起作用,因为:
memo += num if num.is_a?Integer
不是nil
时,num
的值为Integer
。memo
提供给下一次迭代。您的块在第二次迭代时评估为nil
,因此您最终将尝试评估:
nil += 2 if 2.is_a? Integer
并且有你的NoMethodError。
为了清楚起见,您最好分两步执行此操作:
mixed_array.select { |e| e.is_a? Integer }.inject(:+)
或者甚至是更宽松的版本:
mixed_array.select { |e| e.is_a? Numeric }.inject(:+)
或使用较新版本的Ruby:
mixed_array.select { |e| e.is_a? Numeric }.sum
如果你没有教条地反对三元,那么你也可以这样说:
mixed_array.inject(0) { |memo, num| memo + (num.is_a?(Integer) ? num : 0) }
mixed_array.sum { |e| e.is_a?(Integer) ? e : 0 }
如果您知道mixed_array
的非数字元素是看起来不像数字或以数字开头的字符串(即没有'0'
,'11 pancakes'
,...... )然后你可以说:
mixed_array.map(&:to_i).inject(:+)
mixed_array.inject(0) { |memo, num| memo + num.to_i }
...
但这可能做了太多假设。
答案 2 :(得分:0)
如果您将其视为两阶段操作而不是一阶段操作,则可以更轻松地执行此操作:
mixed_array=[1,'cat',2]
mixed_array.grep(Integer).inject(0, :+)
# => 3
这将过滤掉数组中的所有非Integer元素,并将其余元素添加到一起。
请记住inject
将前一次迭代的返回值作为下一次迭代的种子。您的if
子句必须返回备用值。如果您修复它,最终会得到这个:
memo += num.is_a?(Integer) ? num : 0
您还可以使用足够好的解决方案,例如:
memo += num.to_i
取决于您尝试筛选的数据类型。
答案 3 :(得分:0)
mixed_array = [1, 'cat', 2, [3, 4], :a, { b: 5, c: 6 }, 7]
mixed_array.reduce(0) { |tot, obj| tot += Integer(obj) rescue 0 }
#=> 10
当数组可能包含一个或多个浮点数并且您想要返回一个浮点数时:
mixed_array = [1, 'cat', 2, [3, 4], :a, { b: 5, c: 6 }, 7, 8.123]
mixed_array.reduce(0) { |tot, obj| tot += Float(obj) rescue 0 }
#=> 18.122999999999998