需要一个简单的注射方法的解释

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

我正在看这个代码,但是我的大脑并没有注意到数字10如何成为结果。 有人会介意在这里解释发生了什么?

您可以将第一个块参数视为累加器:块的每个运行结果都存储在累加器中,然后传递给块的下一个执行。 在上面显示的代码的情况下,您将累加器的结果默认为0.每个块的运行将给定的数字添加到当前总数,然后将结果存回累加器。 下一个块调用具有这个新的值,添加到它,再次存储它,并重复。

在进程结束时,inject将返回累加器,在这种情况下,累加器是数组中所有值的总和,即10。

下面是另一个简单的例子,用一个对象数组来创build一个哈希表,并用string表示键入:

 [1,"a",Object.new,:hi].inject({}) do |hash, item| hash[item.to_s] = item hash end 

在这种情况下,我们将累加器默认为一个空的哈希值,然后在每次执行该块时填充它。 注意,我们必须把散列作为块的最后一行返回,因为块的结果将被存回累加器中。

inject取值(以你的例子中的0开始)和一个块,并且它为列表的每个元素运行该块一次。

  1. 在第一次迭代时,它传入你提供的值作为起始值和列表的第一个元素,并保存块返回的值(在本例中为result + element )。
  2. 然后再次运行该块,将第一次迭代的结果作为第一个参数传入,将第二个元素作为第二个参数传入,再次保存结果。
  3. 它继续这种方式,直到它消耗了列表中的所有元素。

解释这个最简单的方法可能是显示每个步骤如何工作,例如, 这是一个假想的步骤,显示如何评估这个结果:

 [1, 2, 3, 4].inject(0) { |result, element| result + element } [2, 3, 4].inject(0 + 1) { |result, element| result + element } [3, 4].inject((0 + 1) + 2) { |result, element| result + element } [4].inject(((0 + 1) + 2) + 3) { |result, element| result + element } [].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element } (((0 + 1) + 2) + 3) + 4 10 

代码遍历数组中的四个元素,并将之前的结果添加到当前元素:

  • 1 + 2 = 3
  • 3 + 3 = 6
  • 6 + 4 = 10

他们说什么,但是也要注意,你并不总是需要提供一个“起始价值”:

 [1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

是相同的

 [1, 2, 3, 4].inject { |result, element| result + element } # => 10 

试试吧,我会等的。

当没有参数传入注入,前两个元素被传递到第一次迭代。 在上面的例子中,结果是1,第一次元素是2,所以对块的调用less一个。

你放入()注入的数字代表一个起始位置,它可以是0或1000.在pipe道内有两个占位符| x,y |。 x =你在.inject('x')里面有什么数字,secound代表你的对象的每个迭代。

[1, 2, 3, 4].inject(5) { |result, element| result + element } # => 15

1 + 5 = 6 2 + 6 = 8 3 + 8 = 11 11 + 4 = 15

注入方法的语法如下所示:

inject (value_initial) { |result_memo, object| block }

让我们来解决上面的例子

[1, 2, 3, 4].inject(0) { |result, element| result + element }

这给出了10作为输出。

所以,在开始之前,让我们看看每个variables中存储的值是什么:

结果= 0零来自注入(值),它是0

element = 1它是数组的第一个元素。

奥基! 所以,让我们开始了解上面的例子

步骤:1 [ 1 , 2, 3, 4].inject( 0 ) { | 0 , 1 | 0 + 1 } [ 1 , 2, 3, 4].inject( 0 ) { | 0 , 1 | 0 + 1 }

步骤:2 [1, 2 , 3, 4].inject(0) { | 1 , 2 | 1 + 2 } [1, 2 , 3, 4].inject(0) { | 1 , 2 | 1 + 2 }

步骤:3 [1, 2, 3 , 4].inject(0) { | 3 , 3 | 3 + 3 } [1, 2, 3 , 4].inject(0) { | 3 , 3 | 3 + 3 }

步骤:4 [1, 2, 3, 4 ].inject(0) { | 6 , 4 | 6 + 4 } [1, 2, 3, 4 ].inject(0) { | 6 , 4 | 6 + 4 }

步骤:5 [1, 2, 3, 4].inject(0) { | 10 , Now no elements left in the array, so it'll return 10 from this step | } [1, 2, 3, 4].inject(0) { | 10 , Now no elements left in the array, so it'll return 10 from this step | }

这里的Bold-Italic值是从数组中获取的元素,简单的粗体值就是结果值。

我希望你了解#inject方法的#ruby

注入应用该块

 result + element 

到数组中的每个项目。 对于下一个项目(“元素”),从块返回的值是“结果”。 你调用它的方式(带有参数),“结果”以该参数的值开始。 所以效果是增加了元素。

 [1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10 

相当于以下内容:

 def my_function(r, e) r+e end a = [1, 2, 3, 4] result = 0 a.each do |value| result = my_function(result, value) end 

tldr; injectmap不同之处在于一个重要的方法: inject返回块的最后一次执行的值,而map返回它迭代的数组。

不仅如此 ,每个块执行的值通过第一个parameter passing给下一个执行(在本例中为result ),您可以初始化该值( (0)部分)。

你上面的例子可以用这样的map来写:

 result = 0 # initialize result [1, 2, 3, 4].map { |element| result += element } # result => 10 

同样的效果,但inject更简洁。

你会经常发现一个任务发生在地图块中,而一个评估发生在inject块中。

您select哪种方法取决于您想要的result范围。 什么时候使用它会是这样的:

 result = [1, 2, 3, 4].inject(0) { |x, element| x + element } 

你可能就像所有的一样,“看着我,我只是把它们合并成一行”,但是你也暂时把x内存分配给了一个没有必要的scratchvariables,因为你已经有result了。

[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10

用简单的英语,你正在经历(迭代)这个数组( [1,2,3,4] )。 你将遍历这个数组4次,因为有4个元素(1,2,3和4)。 注入方法有1个参数(数字0),您将该参数添加到第1个元素(0 + 1。这等于1)。 1保存在“结果”中。 然后你把这个结果(1)加到下一个元素(1 + 2。这是3)。 现在将被保存为结果。 继续:3 + 3等于6.最后,6 + 4等于10。

这段代码不允许不传递起始值的可能性,但可能有助于解释发生了什么。

 def incomplete_inject(enumerable, result) enumerable.each do |item| result = yield(result, item) end result end incomplete_inject([1,2,3,4], 0) {|result, item| result + item} # => 10 

从这里开始,然后查看所有采用块的方法。 http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject

这是混淆你的块或为什么你有一个价值的方法? 好问题,但。 那里的操作员方法是什么?

 result.+ 

它是从什么开始的?

 #inject(0) 

我们能做到吗?

 [1, 2, 3, 4].inject(0) { |result, element| result.+ element } 

这是否工作?

 [1, 2, 3, 4].inject() { |result = 0, element| result.+ element } 

你看到我正在构build这个想法,它只是将数组的所有元素相加,并在文档中看到的备忘录中产生一个数字。

你总是可以做到这一点

  [1, 2, 3, 4].each { |element| p element } 

看到数组的枚举被迭代。 这是基本的想法。

这只是注入或减less给你一个备忘录或累加器发送出去。

我们可以尝试得到一个结果

 [1, 2, 3, 4].each { |result = 0, element| result + element } 

但没有回来,所以这只是像以前一样行事

 [1, 2, 3, 4].each { |result = 0, element| p result + element } 

在元素检查器块中。

还有另一种forms的.inject()方法,这是非常有用的[4,5] .inject(&:+)这将加起来该区域的所有元素

如果您熟悉其他语言,只需reducefold

是这样的:

 [1,2,3,4].inject(:+) => 10