[英]How to group multiple hashes with same key into an array of hashes
從散列數組開始:
roles =[
{:id=>1, :name=>"alpha", :gid=>1},
{:id=>2, :name=>"beta", :gid=>2},
{:id=>3, :name=>"delta", :gid=>1},
{:id=>4, :name=>"epsilon", :gid=>1},
{:id=>5, :name=>"zeta", :gid=>3}
]
我試圖得到另一種結構:
groups = [
{:gid=>1, :roles=>[
{:id=>1, :name=>"alpha"},
{:id=>3, :name=>"delta"},
{:id=>4, :name=>"epsilon"}]},
{:gid=>2, :roles=>[{:id=>2, :name=>"beta"}]},
{:gid=>3, :roles=>[{:id=>5, :name=>"zeta"}]}
]
答案-所有答案都輸出相同..但是我必須投票最快的答案..
time1 = Benchmark.measure do
(1..10000).each do
roles.group_by { |e| e.slice(:gid) }.map{
|k,v| k.merge(:roles => v.map { |e| e.except(:gid)}) }
end
end
puts time1
user system total real
1.150000 0.010000 1.160000 ( 1.165781)
time2 = Benchmark.measure do
(1..10000).each do
roles.group_by{|el| el[:gid]}.map{|gid, els|
{gid: gid, roles: els.map{ |el| { id: el[:id], name: el[:name]}}}}
end
end
puts time2
user system total real
0.270000 0.000000 0.270000 ( 0.278286)
time3 = Benchmark.measure do
(1..10000).each do
roles.group_by{|h| h.delete(:gid)}.map{|k, v| {gid: k, roles: v}}
end
end
puts time3
user system total real
0.130000 0.000000 0.130000 ( 0.134478)
您的問題的答案是:
gid = nil
h = [
{:id=>1, :name=>"alpha", :gid=>1},
{:id=>3, :name=>"delta", :gid=>1},
{:id=>4, :name=>"epsilon", :gid=>1}
]
.each{|h| gid = h.delete(:gid)}
{gid: gid, roles: h}
但是整個事情可以這樣完成:
roles.group_by{|h| h.delete(:gid)}.map{|k, v| {gid: k, roles: v}}
roles = [
{:id => 1, :name=>"alpha", :gid=>1},
{:id => 2, :name=>"beta", :gid=>2},
{:id => 3, :name=>"delta", :gid=>1},
{:id => 4, :name=>"epsilon", :gid=>1},
{:id => 5, :name=>"zeta", :gid=>3}
]
roles.group_by do |el|
el[:gid]
end.map do |gid, els|
{
gid: gid,
roles: els.map{ |el| { id: el[:id], name: el[:name] } }
}
end
帶有ActiveSupport的Ruby 1.8.7解決方案,方法為slice()
和exception except()
。
require 'rubygems'
require 'active_support/all'
roles.group_by { |e| e.slice(:gid) }.
map { |k,v| k.merge(:roles => v.map { |e| e.except(:gid)}) }
#=> [{:gid=>1, :roles=>[{:name=>"alpha", :id=>1},
# {:name=>"delta", :id=>3},
# {:name=>"epsilon", :id=>4}]},
# {:gid=>2, :roles=>[{:name=>"beta", :id=>2}]},
# {:gid=>3, :roles=>[{:name=>"zeta", :id=>5}]}]
這使用Hash#update (也稱為merge!
)的形式,該形式采用一個塊來確定要合並的兩個哈希中都存在的鍵的值。 這里的塊是:
{ |k,ov,nv| { :gid=>ov[:gid], :roles=>ov[:roles]+nv[:roles] } }
其中k
是公共密鑰, ov
是正在構造的密鑰的值, nv
是正在合並的哈希的值。
計算:
roles.each_with_object({}) do |g,h|
h.update(g[:gid]=>{ :gid=>g[:gid],
:roles=>[{:id=>g[:id], :name=>g[:name]}]
}
) { |k,ov,nv| { :gid=>ov[:gid], :roles=>ov[:roles]+nv[:roles] } }
end.values
#=> [{:gid=>1, :roles=>[{:id=>1, :name=>"alpha"},
# {:id=>3, :name=>"delta"},
# {:id=>4, :name=>"epsilon"}]},
# {:gid=>2, :roles=>[{:id=>2, :name=>"beta"}]},
# {:gid=>3, :roles=>[{:id=>5, :name=>"zeta"}]}]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.