红宝石中减少/注入方法的更深层解释

时间:2018-12-21 13:21:23

标签: ruby functional-programming reduce

一段时间以来,我一直在绞尽脑汁。

使用reduce时-为什么不执行块中定义的操作就返回第一个元素?还是我缺少reduce如何工作的关键点?

在以下示例中:

arr = [1, 3, 5]

arr.reduce {|sum, n| sum + (n * 3) }
#=> 25

我希望结果为 27

因为:

0 + (1 * 3) = 3
3 + (3 * 3) = 12
12 + (5 * 3) = 27

一段时间后,我发现在第一个“滴答”中-数组中的对象只是被添加到总和中而不是被相乘。这样计算起来更像:

??? = 1
1 + (3 * 3) = 10
10 + (5 * 3) = 25

有人可以帮我弄清楚我要走的路吗?

3 个答案:

答案 0 :(得分:6)

它在the docs中。

  

如果您未明确指定备忘录的初始值,则将集合的第一个元素用作备忘录的初始值。

答案 1 :(得分:4)

我对 Ruby 注入/减少方法中的默认值有类似的问题,所以我尝试visualize it

default values vizualized

答案 2 :(得分:1)

在这种情况下,我认为解释是对方法的帮助:

[1] pry(main)> cd Array
[2] pry(Array):1> ? reduce

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

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

The inject and reduce methods are aliases. There
is no performance benefit to either.

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 the first element of collection is used as the initial value
of memo.


   # 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                                        #=> "sheep"

因此,您需要将第一个备忘录指定为0,在这种情况下,该备忘录为:

[4] pry(Array):1> [1,3,5].reduce(0) {|sum, n| sum + (n * 3) }
=> 27