我正在努力更好地理解哈希,并且我遇到了一些问题,其中我有一个带有重复项目的集合,我需要返回这些项目的哈希值,同时添加一个计算这些项目的密钥。例如...
我有一个杂货项目的散列,每个项目指向另一个描述每个项目的各种属性的散列。
groceries = [
{"avocado" => {:price => 3.0, :on_sale => true}},
{"tomato" => {:price => 1.0, :on_sale => false}},
{"avocado" => {:price => 3.0, :on_sale => true}},
{"kale" => {:price => 5.0, :on_sale => false}}
]
而且我想要更新的杂货......
groceries_updated = {
"avocado" => {:price => 3.0, :on_sale => true, :count => 2},
"tomato" => {:price => 1.0, :on_sale => false, :count => 1},
"kale" => {:price => 5.0, :on_sale => false, :count => 1}
}
我最初的方法是首先通过迭代原始哈希来创建我的新哈希,所以我会有这样的东西。然后我会再次遍历原始哈希并在我的新哈希中增加计数器。我想知道这是否可以在散列的一次迭代中完成。我也尝试过使用#each_with_object方法,但我还需要更好地理解这些参数。我对#each_with_object的尝试导致了一个哈希数组,其中添加了:count键,但没有合并。
def consolidate_cart(array)
array.each do |hash|
hash.each_with_object(Hash.new {|h,k| h[k] = {price: nil, clearance: nil, count: 0}}) do |(item, info), obj|
puts "#{item} -- #{info}"
puts "#{obj[item][:count] += 1}"
puts "#{obj}"
end
end
end
您可以使用inject
以下列方式构建整合的杂货:
groceries = [
{"avocado" => {:price => 3.0, :on_sale => true}},
{"tomato" => {:price => 1.0, :on_sale => false}},
{"avocado" => {:price => 3.0, :on_sale => true}},
{"kale" => {:price => 5.0, :on_sale => false}}
]
groceries_updated = groceries.inject({}) do |consolidated, grocery|
item = grocery.keys.first
consolidated[item] ||= grocery[item].merge(count: 0)
consolidated[item][:count] += 1
consolidated
end
inject
获取您要构建的对象的初始状态(在本例中为{}
)和将为数组的每个元素调用的块。该块的目的是修改/填充对象。关于如何使用inject
的良好描述可以找到here。
在您的情况下,块将向哈希添加新项目或增加其count
(如果已存在)。上面的代码将向哈希添加一个新项目,count
为0,只有当它不存在时(这就是||=
所做的)。然后它将增加count
。
需要注意的一点是,原始groceries
数组中的值可能不同(例如,一个avocado
条目可能具有3.0的price
,另一个price
为3.5)。 groceries_updated
中的值将包含原始数组中的第一个值。
单行(几乎只是在一些链式块中分开):
groceries.
group_by { |h| h.keys.first }.
transform_values { |v| v.first.values.first.merge(count: v.size) }
说明:
第一个块根据(假设的单个)哈希键将列表拆分为多个值:
{
"avocado" => [
{"avocado" => {:price => 3.0, :on_sale => true}},
{"avocado" => {:price => 3.0, :on_sale => true}}
],
"tomato" => [
{"tomato" => {:price => 1.0, :on_sale => false}}
], ...
}
第二个块占用一个值
[
{"avocado" => {:price => 3.0, :on_sale => true}},
{"avocado" => {:price => 3.0, :on_sale => true}}
]
读取第一个项目的所谓单个值,并与总计数合并。
:那么: