each_with_object应该如何工作?

我想知道如何使用each_with_object

我试着用它来做一个非常简单的总和,所以我写道:

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

嘿,我认为结果将是6! 我的错误在哪里?

each_with_object不适用于整数等不可变对象。

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

这是因为each_with_object遍历集合,将每个元素和给定对象传递给块。 它不会在每次迭代后更新对象的值并返回原始给定对象。

它可以使用哈希,因为哈希键的更改值会自动更改原始对象的值。

 (1..3).each_with_object({:sum => 0}) {|i,hsh| hsh[:sum] += i} #=> {:sum => 6} 

String对象很有趣。 它们是可变的,因此您可能希望以下内容返回“abc”

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

但事实并非如此。 这是因为str += "a"返回一个新对象,原始对象保持不变。 但是如果我们这样做

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

它的工作原理是因为str << "a"修改了原始对象。

有关更多信息,请参阅each_with_object的 ruby文档

为了您的目的,使用注入

 (1..3).inject(0) {|sum,i| sum += i} #=> 6 # or (1..3).inject(:+) #=> 6 

Enumerable#each_with_object的文档非常清楚:

使用给定的任意对象迭代每个元素的给定块,并返回最初给定的对象

在你的情况下, (1..3).each_with_object(0) {|i,sum| sum+=i} (1..3).each_with_object(0) {|i,sum| sum+=i} ,你传递0 ,这是不可变对象。 因此,这里对each_with_object方法的初始对象是0 ,所以方法返回0它在广告中工作。 请参阅下面的each_with_object如何工作,

 (1..3).each_with_object(0) do |e,mem| p "#{mem} and #{e} before change" mem = mem + e p mem end # >> "0 and 1 before change" # >> 1 # >> "0 and 2 before change" # >> 2 # >> "0 and 3 before change" # >> 3 

这意味着在每次传递中, mem都设置为初始传递的对象 。 你可能会想到在第一次传递mem0 ,然后在下一次传递memmem+=e的结果,即mem将是1但是没有,在每次传递mem都是你的初始对象,即0

使用each_with_object一个简单但常见的示例是,您需要根据数组中的元素构建哈希。 通常你会看到类似的东西:

 hash = {} [1, 2, 3, 4].each { |number| hash[number] = number**2 } hash 

使用each_with_object可以避免显式初始化和返回hash变量。

 [1,2,3,4].each_with_object({}) { |number, hash| hash[number] = number**2 } 

我建议阅读injecttapeach_with_index的文档。 当您瞄准简短且可读的代码时,这些方法很有用。