我有一个哈希数组,我基本上想合并并转换为单个哈希,同时我想计算key:value对出现的次数。
原始数组是
cart_items = [
{"AVOCADO" => {:price => 3.0, :clearance => true }},
{"AVOCADO" => {:price => 3.0, :clearance => true }},
{"KALE" => {:price => 3.0, :clearance => false}}
]
我已经尝试过了,但是我没有得到想要的东西。我在下面的尝试,如果有人可以解释我要去哪里的话,那太好了。
我对这个问题的尝试是
def consolidate_cart(items)
### the cart starts as an array of items
## convert the array into a hash`
hashed_items = items.inject(:merge!)
hashed_items.map{|k,v| {k => v, :count => v.length}}
end
consolidate_cart(cart_items)
我希望输出为
{
"AVOCADO" => {:price => 3.0, :clearance => true, :count => 2},
"KALE" => {:price => 3.0, :clearance => false, :count => 1}
}
但是我得到的输出是
[{"AVOCADO"=>{:price=>3.0, :clearance=>true}, :count=>2}, {"KALE"=>{:price=>3.0, :clearance=>false}, :count=>2}]
答案 0 :(得分:1)
您可以将count(v
)的值合并到map
(在v.merge(:count => v.length)
内),这样会将count键添加到v
哈希中,你会得到类似的东西:
[
{"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>2},
{"KALE"=>{:price=>3.0, :clearance=>false, :count=>2}
]
但是无论如何,:count
的值将是错误的。
另一方面,您可以从cart_items中的每个哈希中获取所有键,合并哈希,然后在存储的键数组中合并具有该键计数的新键:
def consolidate_cart(items)
items_keys = items.flat_map(&:keys)
items.inject(:merge).map do |key, value|
{ key => value.merge(count: items_keys.count(key)) }
end
end
p consolidate_cart(cart_items)
# [{"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>2}}, {"KALE"=>{:price=>3.0, :clearance=>false, :count=>1}}]
该方法功能的部分视图:
您映射每个哈希项(items.flat_map(&:keys)
)的键:
["AVOCADO", "AVOCADO", "KALE"]
您在items
(items.inject(:merge)
)内合并哈希:
{"AVOCADO"=>{:price=>3.0, :clearance=>true}, "KALE"=>{:price=>3.0, :clearance=>false}}
当您遍历前一个生成的哈希时,将计数键({ key => value.merge(count: items_keys.count(key)) }
)合并到每个哈希值:
# {:price=>3.0, :clearance=>true}
# {:count=>2}
# => {:price=>3.0, :clearance=>true, :count => 2}
我已经看到我的答案与预期的输出不符。这样做:
def consolidate_cart(items)
items.inject(:merge).each_with_object(items: items.flat_map(&:keys)) do |(k, v), hash|
hash[k] = v.merge(count: hash[:items].count(k))
end.reject { |k, _| k == :items }
end
答案 1 :(得分:0)
我想提出一种方法来考虑同一产品(price
)的clearance
或String
可能不同的情况(因为您不处理数据库ID) ):
cart_items = [
{"AVOCADO" => {:price => 3.0, :clearance => true }},
{"AVOCADO" => {:price => 4.0, :clearance => false }},
{"AVOCADO" => {:price => 3.0, :clearance => true }},
{"AVOCADO" => {:price => 4.0, :clearance => true }},
{"KALE" => {:price => 3.0, :clearance => false}},
{"AVOCADO" => {:price => 4.0, :clearance => true }},
{"AVOCADO" => {:price => 4.0, :clearance => true }}
]
在这种情况下,这是合并的一种可能方法:
cart_items.map{ |h| h.values.first.merge(product: h.keys.first) }
.group_by(&:itself)
.transform_values { |v| v.first.merge(count: v.size)}.values
正在返回:
#=> [{:price=>3.0, :clearance=>true, :product=>"AVOCADO", :count=>2}, {:price=>4.0, :clearance=>false, :product=>"AVOCADO", :count=>1}, {:price=>4.0, :clearance=>true, :product=>"AVOCADO", :count=>3}, {:price=>3.0, :clearance=>false, :product=>"KALE", :count=>1}]
您始终可以附加.group_by{ |h| h[:product] }
来获取
#=> {"AVOCADO"=>[{:price=>3.0, :clearance=>true, :product=>"AVOCADO", :count=>2}, {:price=>4.0, :clearance=>false, :product=>"AVOCADO", :count=>1}, {:price=>4.0, :clearance=>true, :product=>"AVOCADO", :count=>3}], "KALE"=>[{:price=>3.0, :clearance=>false, :product=>"KALE", :count=>1}]}
或者针对您帖子中的购物车:
#=> {"AVOCADO"=>[{:price=>3.0, :clearance=>true, :product=>"AVOCADO", :count=>2}], "KALE"=>[{:price=>3.0, :clearance=>false, :product=>"KALE", :count=>1}]}
与所需的输出不完全相同,但这可能很有用。是否。
答案 2 :(得分:0)
cart_items.each_with_object(Hash.new(0)) { |g,h| h[g] += 1 }.
map { |g,cnt| { g.keys.first=>g.values.first.merge(count: cnt) } }
#=> [{"AVOCADO"=>{:price=>3.0, :clearance=>true, :count=>2}},
# {"KALE"=>{:price=>3.0, :clearance=>false, :count=>1}}]
Hash.new(0)
有时称为计数哈希。请参见Hash::new的形式,该形式的参数等于哈希的默认值。我们获得:
cart_items.each_with_object(Hash.new(0)) { |g,h| h[g] += 1 }
#=> {{"AVOCADO"=>{:price=>3.0, :clearance=>true}}=>2,
# {"KALE"=>{:price=>3.0, :clearance=>false}}=>1}
答案 3 :(得分:0)
cart_items.group_by(&:itself).map{ |item, group| item[item.keys.first][:count] = group.size; item}