.inject vs .each_with_object

时间:2016-08-25 17:52:54

标签: ruby

我知道each_with_object不适用于integer等不可变对象。

例如(1..3).each_with_object(0) {|i,sum| sum += i} #=> 0

我们可以通过注入来解决这个问题,总和将是6。太好了!

让我们再举一个例子

("a".."c").each_with_object("") {|i,str| str += i} # => ""

这不起作用,因为当我们str+=i时,我们制作一个新对象

相反,我们需要做

("a".."c").each_with_object("") {|i,str| str << i} # => "abc"

为什么当我通过以下两种方式inject获得奇怪的结果时

("a".."c").inject("") {|i,str| str += i} # => cba

("a".."c").inject("") {|i,str| str << i} # => ERROR

为什么第一次打印abc反向?为什么第二个错误?

我知道我们应该将.each_with_object用于可变对象,并将inject用于不可变对象(如Integer),但是我可以使用 .inject对于可变对象以及.each_with_object一样?任何人都可以解释这些结果吗?

1 个答案:

答案 0 :(得分:2)

  

为什么第一次打印abc反向?

参数是倒退的。 请参阅Enumerable#inject

打印istr显示问题。

$ ruby -e '("a".."c").inject("") {|i,str| puts "i   = #{i}"; puts "str = #{str}"; ret = str += i; puts "ret = #{ret}\n\n"; ret }'
i   = 
str = a
ret = a

i   = a
str = b
ret = ba

i   = ba
str = c
ret = cba

i是最后一次通过块返回的累计和。 str是下一个值。您将之前的累计值添加到下一个累计值的末尾。你有倒退的论点。第一个是总和,第二个是下一个元素。

当纠正后,它可以正常工作。

$ ruby -e 'puts ("a".."c").inject("") {|sum,i| sum += i}'
abc

此外, 它是使用 的块的返回值。改变str没有任何效果,它只会使事情进一步混淆。

$ ruby -e 'puts ("a".."c").inject("") {|sum,i| sum + i}'
abc
  

为什么第二个错误?

不是,不是在Ruby 2.0.0和2.2.4中。但它有倒退的问题。

$ ruby -e 'puts ("a".."c").inject("") {|i,str| str << i} # => ERROR'
cba

$ ruby -v
ruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-darwin15]