2016-08-24 86 views
0

我正在使用这个注入方法来将一个运行的值总和放入一个数组中。我想弄清楚为什么我得到一个错误。为什么在Ruby中使用注入时会出现'typeerror'?

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) 

当打破这种方法了,这不就是一样增加了两个整数和补充说,到一个数组?我在这里有点困惑。谢谢您的帮助。

+0

为什么不尝试更简单的解决方案?例如'a.map.with_index {| _,i |一个[0..i] .reduce(:+)}'这将通过减少当前元素和所有前面的元素或甚至sum = 0映射到一个数组中。 a.map {| e | sum + = e}' – engineersmnky

回答

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] 

注意,我移动注入的结果阵列的结果一样,所以这也包括终值,否则你只能有四个值,并会错过最后的(15)值。

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,所以我们加12得到3然后把它推到数组上,返回[1,3]

第三次成块,results[1,3],和n3,所以它返回[1,3,6]。等等。

+0

'results.last || 0'会做那种粗糙的工作,如果......然后呢。 – tadman

+0

好点,编辑。我从'results.empty开始? ? 0:...'但那仍然是粗糙的... –

+0

不错的答案,非常漂亮! – SteveTurczyn

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] 
0

根据ri,你必须从注入块返回计算结果。

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 

希望它能帮助:

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 

所以,如果你返回计算结果为每次迭代,这样的事情你的样品是可行的。

+0

逐字引用文档是回答事情的一种懒惰方式。 – tadman

相关问题