`each_with_object(Hash.new([]))如何工作?

Jum*_*ton 1 ruby arrays iteration hash

我编写了这段代码来制作哈希,其中键是类别(水果或蔬菜),值是该类别中的项目数组.

food = ["fruit:orange", "fruit:apple", "fruit:cherry", "veg:pea", "veg:parsley"]

food.each_with_object(Hash.new([])) do |food_item, hash|
  category, value = food_item.split(":")
  hash[category] = hash[category].push(value)
end
Run Code Online (Sandbox Code Playgroud)

这就是我得到的:

# =>
{
  "fruit" => ["orange", "apple", "cherry", "pea", "parsley"],
  "veg"   => ["orange", "apple", "cherry", "pea", "parsley"]
} 
Run Code Online (Sandbox Code Playgroud)

但我期待这个:

{
  "fruit"=> ["orange", "apple", "cherry"],
  "veg"  => ["pea", "parsley"]
} 
Run Code Online (Sandbox Code Playgroud)

第一次迭代应该产生{ fruit: ["orange"] },第二{ fruit: ["orange", "apple"] }次迭代......第四次迭代应该创建veg键,然后继续.蔬菜如何最终被推到水果阵列,反之亦然?

Ale*_*kin 5

哇,评论中莎士比亚的激情是什么.好吧,我可以重现一个问题,我会提供一个答案.

根据以下文件Hash#new:

如果指定了obj,则此单个对象将用于所有默认值.

也就是说,所有新创建的哈希元素将共享唯一的数组实例.换句话说,根据规范,在这种情况下,您的哈希值将根据定义始终相同.要产生您最初想要的东西,只需在每次需要时使用的empty实例初始化哈希值Array:

food = ["fruit:orange", "fruit:apple", "fruit:cherry", "veg:pea", "veg:parsley"]
food.each_with_object({}) do |food_item, hash|
  category, value = food_item.split(":")
  (hash[category] ||= []).push(value)
end
#? {"fruit"=>["orange", "apple", "cherry"], "veg"=>["pea", "parsley"]}
Run Code Online (Sandbox Code Playgroud)