【问题标题】:How does `each_with_object(Hash.new([]))` work? [duplicate]`each_with_object(Hash.new([]))` 是如何工作的? [复制]
【发布时间】:2023-03-03 00:05:01
【问题描述】:

我编写这段代码是为了生成一个哈希,其中键是类别(水果或蔬菜),值是该类别中的项目数组。

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

这是我得到的:

# =>
{
  "fruit" => ["orange", "apple", "cherry", "pea", "parsley"],
  "veg"   => ["orange", "apple", "cherry", "pea", "parsley"]
} 

但我预料到了:

{
  "fruit"=> ["orange", "apple", "cherry"],
  "veg"  => ["pea", "parsley"]
} 

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

【问题讨论】:

  • 您的屏幕截图中的结果与您问题前面所述的结果不符。

标签: ruby arrays iteration hash


【解决方案1】:

哇,在 cmets 中,莎士比亚的热情是怎样的。好吧,我可以重现问题并提供答案。

根据Hash#new上的文档:

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

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

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"]}

【讨论】:

    【解决方案2】:

    hash["fruit"] 和 hash["veg"] 的数组是完全相同的对象。

    您需要像这样为每个键创建新数组。

    food.each_with_object(Hash.new{|h,k| h[k]=[]}) do |food_item, hash|
      category, value = food_item.split(":")
      hash[category] = hash[category].push(value)
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-22
      • 1970-01-01
      • 2016-01-19
      • 2014-08-25
      • 2011-10-02
      • 2011-10-22
      • 2011-04-15
      • 2011-04-26
      相关资源
      最近更新 更多