为什么在Ruby中使用inject时会出现'typeerror'?

时间:2016-08-24 15:37:41

标签: ruby

我正在使用这种注入方法将一组运行的值组合成一个数组。我想弄清楚为什么我会收到错误。

def running_totals(myarray)
 results = []
  myarray.inject([]) do |sum,n|
    results << sum + n
  end
  results
end

p running_totals([1,2,3,4,5])

我收到错误

in `+': no implicit conversion of Fixnum into Array (TypeError)

当打破这个方法时,这不是添加两个整数并将其添加到数组中吗?我在这里有点困惑。谢谢你的帮助。

4 个答案:

答案 0 :(得分:3)

在第一次迭代中,sum将是一个数组(正如您在调用inject([])时将数组指定为默认值),并尝试向其中添加数字。在results << sum + n声明中

相反,将初始值设置为0,然后添加,然后将结果添加到数组中,然后确保让sum传递到下一次注入迭代。

def running_totals(myarray)
  results = []
  myarray.inject(0) do |sum,n| # First iteration sum will be 0.
    sum += n # Add value to sum.
    results << sum # Push to the result array.
    sum # Make sure sum is passed to next iteration.
  end
  results
end

p running_totals([1,2,3,4,5]) #=> [1, 3, 6, 10, 15]

答案 1 :(得分:2)

results << sum + n的结果是一个数组results,而这就是取代sum值,因此您尝试将fixnum n添加到下一次迭代中一个数组sum ...加上你将sum的值初始化为数组没有帮助。

确保注入块中最后执行的语句是您想要的累计值。

def running_totals(myarray)
  results = []
  results << myarray.inject do |sum, n|
    results << sum
    sum + n
  end
  results
end

p running_totals([1,2,3,4,5])
=> [1, 3, 6, 10, 15]

请注意,我也将inject的结果移动到results数组中,因此也包含了最终值,否则你只有四个值并且会丢失final(15)值。

答案 2 :(得分:1)

inject块的返回值在下次调用块时作为第一个参数传递,因此必须匹配。在您的代码中,您将数组作为初始值传递,然后返回一个数组;到现在为止还挺好。但是在代码块中,您将该数组参数(sum)视为一个数字,但不会起作用。试试这个:

def running_totals(myarray)
  myarray.inject([]) do |results,n|
    results << n + (results.last || 0)
  end
end

作为[]的参数传递的inject成为results的第一个值;第一个数组元素(示例中为1)成为n的第一个值。由于results为空,results.lastnil(results.last || 0)的结果为0,我们将其添加到n以获得1,我们推入results,然后从块中返回新修改的数组值。

第二次进入该区块时,results是我们刚刚从第一次传递返回的数组[1],而n2。这一次results.last1而不是nil,因此我们将1添加到2以获取3并将其推送到数组,然后返回[1,3]

第三次进入该区块时,results[1,3]n3,因此返回[1,3,6]。等等。

答案 3 :(得分:0)

根据ri,你必须从inject的块中返回计算结果。

From: enum.c (C Method):
Owner: Enumerable
Visibility: public
Signature: inject(*arg1)
Number of lines: 31

Combines all elements of enum by applying a binary
operation, specified by a block or a symbol that names a
method or operator.

If you specify a block, then for each element in enum
the block is passed an accumulator value (memo) and the element.
If you specify a symbol instead, then each element in the collection
will be passed to the named method of memo.
In either case, the result becomes the new value for memo.
At the end of the iteration, the final value of memo is the
return value for the method.

If you do not explicitly specify an initial value for memo,
then uses the first element of collection is used as the initial value
of memo.

Examples:

   # Sum some numbers
   (5..10).reduce(:+)                            #=> 45
   # Same using a block and inject
   (5..10).inject {|sum, n| sum + n }            #=> 45
   # Multiply some numbers
   (5..10).reduce(1, :*)                         #=> 151200
   # Same using a block
   (5..10).inject(1) {|product, n| product * n } #=> 151200
   # find the longest word
   longest = %w{ cat sheep bear }.inject do |memo,word|
     memo.length > word.length ? memo : word
   end
   longest

因此,如果您为每次迭代返回计算结果,那么您的样本将起作用,如下所示:

def running_totals(myarray)
  results = []
  myarray.inject do |sum,n|
    results << sum + n
    results.last # return computation result back to Array's inject
  end
  results
end

希望它有所帮助。