需要一个简单的注射方法的解释
[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
开始)和一个块,并且它为列表的每个元素运行该块一次。
- 在第一次迭代时,它传入你提供的值作为起始值和列表的第一个元素,并保存块返回的值(在本例中为
result + element
)。 - 然后再次运行该块,将第一次迭代的结果作为第一个参数传入,将第二个元素作为第二个参数传入,再次保存结果。
- 它继续这种方式,直到它消耗了列表中的所有元素。
解释这个最简单的方法可能是显示每个步骤如何工作,例如, 这是一个假想的步骤,显示如何评估这个结果:
[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; inject
与map
不同之处在于一个重要的方法: 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(&:+)这将加起来该区域的所有元素
如果您熟悉其他语言,只需reduce
或fold
。
是这样的:
[1,2,3,4].inject(:+) => 10