我试图弄清楚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
我会假设结果是 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
一个简单但常见的使用示例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 }
我建议阅读inject
,tap
和each_with_index
. 当您的目标是简短易读的代码时,这些方法很有帮助。
的文档Enumerable#each_with_object
非常清楚:
使用给定的任意对象迭代每个元素的给定块,并返回最初给定的对象。
在您的情况下(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
都设置为初始传递的对象。您可能会认为第一遍mem
是0
,然后在下遍mem
中是结果mem+=e
,mem
即将是1
。但是不,在每一遍mem
中都是您的初始对象,即0
。