[英]Convert array into hash and add a counter value to the new hash
我有以下哈希数组:
[
{"BREAD" => {:price => 1.50, :discount => true }},
{"BREAD" => {:price => 1.50, :discount => true }},
{"MARMITE" => {:price => 1.60, :discount => false}}
]
我想将此数组转换为一个散列,其中包含每个项目的计数:
输出:
{
"BREAD" => {:price => 1.50, :discount => true, :count => 2},
"MARMITE" => {:price => 1.60, :discount => false, :count => 1}
}
我尝试了两种方法将数组转换为哈希。
new_cart = cart.inject(:merge)
hash = Hash[cart.collect { |item| [item, ""] } ]
两者都有效,但后来我对如何捕获和传递计数值感到困惑。
预期输出
{
"BREAD" => {:price => 1.50, :discount => true, :count => 2},
"MARMITE" => {:price => 1.60, :discount => false, :count => 1}
}
我们得到数组:
arr = [
{"BREAD" => {:price => 1.50, :discount => true }},
{"BREAD" => {:price => 1.50, :discount => true }},
{"MARMITE" => {:price => 1.60, :discount => false}}
]
并假设每个散列都有一个键,如果两个散列具有相同的(单个)键,则该键的值在两个散列中是相同的。
第一步是创建一个空哈希,将添加键值对:
h = {}
现在我们循环遍历arr
来构建哈希h
。 我添加了一个puts
语句来显示计算中的中间值。
arr.each do |g|
k, v = g.first
puts "k=#{k}, v=#{v}"
if h.key?(k)
h[k][:count] += 1
else
h[k] = v.merge({ :count => 1 })
end
end
显示:
k=BREAD, v={:price=>1.5, :discount=>true}
k=BREAD, v={:price=>1.5, :discount=>true}
k=MARMITE, v={:price=>1.6, :discount=>false}
并返回:
#=> [{"BREAD" =>{:price=>1.5, :discount=>true}},
# {"BREAD" =>{:price=>1.5, :discount=>true}},
# {"MARMITE"=>{:price=>1.6, :discount=>false}}]
each
总是返回它的接收者(这里是arr
),这不是我们想要的。
h #=> {"BREAD"=>{:price=>1.5, :discount=>true, :count=>2},
# "MARMITE"=>{:price=>1.6, :discount=>false, :count=>1}}
是我们需要的结果。 看到哈希#key了吗? (又名has_key?
)、 Hash#[] 、 Hash#[]=和Hash#merge 。
现在让我们将其包装在一个方法中。
def hashify(arr)
h = {}
arr.each do |g|
k, v = g.first
if h.key?(k)
h[k][:count] += 1
else
h[k] = v.merge({ :count=>1 })
end
end
h
end
hashify(arr)
#=> {"BREAD"=>{:price=>1.5, :discount=>true, :count=>2},
# "MARMITE"=>{:price=>1.6, :discount=>false, :count=>1}}
Rubyists经常使用Enumerable#each_with_object方法来简化。
def hashify(arr)
arr.each_with_object({}) do |g,h|
k, v = g.first
if h.key?(k)
h[k][:count] += 1
else
h[k] = v.merge({ :count => 1 })
end
end
end
比较这两种方法以识别它们的差异。 参见Enumerable#each_with_object 。
当这里的键是符号时,Ruby 允许您使用简写{ count: 1 }
来表示{ :count=>1 }
。 此外,当散列是参数时,她允许您编写:count = 1
或count: 1
而不使用大括号。 例如,
{}.merge('cat'=>'meow', dog:'woof', :pig=>'oink')
#=> {"cat"=>"meow", :dog=>"woof", :pig=>"oink"}
可能更常见的形式是count: 1
当键是符号时,当哈希是参数时省略大括号。
这是您可能会看到的进一步改进。 首先创建
h = arr.group_by { |h| h.keys.first }
#=> {"BREAD" =>[{"BREAD"=>{:price=>1.5, :discount=>true}},
# {"BREAD"=>{:price=>1.5, :discount=>true}}],
# "MARMITE"=>[{"MARMITE"=>{:price=>1.6, :discount=>false}}]}
参见Enumerable#group_by 。 现在将值(数组)转换为它们的大小:
counts = h.transform_values { |arr| arr.size }
#=> {"BREAD"=>2, "MARMITE"=>1}
可以写成缩写形式:
counts = h.transform_values(&:size)
#=> {"BREAD"=>2, "MARMITE"=>1}
请参阅Hash#transform_values 。 我们现在可以写:
uniq_arr = arr.uniq
#=> [{"BREAD"=>{:price=>1.5, :discount=>true}},
#= {"MARMITE"=>{:price=>1.6, :discount=>false}}]
uniq_arr.each_with_object({}) do |g,h|
puts "g=#{g}"
k,v = g.first
puts " k=#{k}, v=#{v}"
h[k] = v.merge(counts: counts[k])
puts " h=#{h}"
end
显示:
g={"BREAD"=>{:price=>1.5, :discount=>true}}
k=BREAD, v={:price=>1.5, :discount=>true}
h={"BREAD"=>{:price=>1.5, :discount=>true, :counts=>2}}
g={"MARMITE"=>{:price=>1.6, :discount=>false}}
k=MARMITE, v={:price=>1.6, :discount=>false}
h={"BREAD"=>{:price=>1.5, :discount=>true, :counts=>2},
"MARMITE"=>{:price=>1.6, :discount=>false, :counts=>1}}
并返回:
#=> {"BREAD"=>{:price=>1.5, :discount=>true, :counts=>2},
# "MARMITE"=>{:price=>1.6, :discount=>false, :counts=>1}}
请参阅Array#uniq 。
这做到了:
arr = [
{ bread: { price: 1.50, discount: true } },
{ bread: { price: 1.50, discount: true } },
{ marmite: { price: 1.60, discount: false } }
]
获取每次出现的哈希计数,添加为键值对并存储:
h = arr.uniq.each { |x| x[x.first.first][:count] = arr.count(x) }
然后将散列转换为数组,展平为单个数组,然后构造一个散列:
Hash[*h.collect(&:to_a).flatten]
#=> {:bread=>{:price=>1.50, :discount=>true, :count=>2}, :marmite=>{:price=>1.60, :discount=>false, :count=>1}}
从这里结合了几个不错的想法: https ://raycodingdotnet.wordpress.com/2013/08/05/array-of-hashes-into-single-hash-in-ruby/和这里: http://carol- nichols.com/2015/08/07/ruby-occurrence-couting/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.