在混合数组中添加数字

时间:2017-02-20 18:31:12

标签: ruby

我对此代码的期望是数字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

4 个答案:

答案 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)

你所拥有的东西不起作用,因为:

  1. memo += num if num.is_a?Integer不是nil时,num的值为Integer
  2. 每个块的值作为memo提供给下一次迭代。
  3. 您的块在第二次迭代时评估为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 

请参阅Kernel::IntegerKernel::Float