[英]How to merge two arrays of hashes by the same pair of key and value ruby
我是紅寶石的新手。 我有兩個哈希:
f = { "server"=>[{ "hostname"=>"a1", "ip"=>"10" }, {"hostname"=>"b1", "ip"=>"10.1" }] }
g = { "admin" =>[{ "name"=>"adam", "mail"=>"any", "hostname"=>"a1" },
{ "name"=>"mike", "mail"=>"id", "hostname"=>"b1"}]}
我想得到另一個像這樣的哈希:
{ "data" => [{"hostname"=>"a1", "ip"=>"10", "name" =>"adam", "mail"=>"any"},
{"hostname"=>"b1", "ip"=>"10.1", "name" =>"mike", "mail"=>"id"}]}
對"hostname"=>"something"
總是匹配兩個數組的哈希值。 我試過這樣的事情:
data = server.merge(admin)
但它並不容易,因為你認為它不起作用。 你能幫我合並這些哈希並解釋你未來的表現嗎?
我現在能想到的一種快速方式如下:
servers = { "server" => [{"hostname"=>"a1", "ip"=>"10"}, {"hostname"=>"b1", "ip"=>"10.1"}]}
admins = { "data" => [{"hostname"=>"a1", "ip"=>"10", "name" =>"adam", "mail"=>"any"}, {"hostname"=>"b1", "ip"=>"10.1", "name" =>"mike", "mail"=>"id"}]}
# FYI: you can just use arrays for representing the above data, you don't necessarily need a hash.
list_of_entries = (servers.values + admins.values).flatten
grouped_by_hostname_entries = list_of_entries.group_by { |h| h['hostname'] }
grouped_by_hostname_entries.map { |_, values| values.inject({}, :merge) }
#=> [{"hostname"=>"a1", "ip"=>"10", "name"=>"adam", "mail"=>"any"}, {"hostname"=>"b1", "ip"=>"10.1", "name"=>"mike", "mail"=>"id"}]
代碼和示例
ff = f["server"].each_with_object({}) { |g,h| h[g["hostname"]] = g }
#=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}, "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
{ "data"=>g["admin"].map { |h| h.merge(ff[h["hostname"]]) } }
#=> {"data"=>[{"name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10"},
# {"name"=>"mike", "mail"=>"id", "hostname"=>"b1", "ip"=>"10.1"}]}
說明
我們想要產生一個哈希
{ "data"=>arr }
哪里
arr #=> [{ "name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10" },
# { "name"=>"mike", "mail"=>"id", "hostname"=>"b1", "ip"=>"10.1" }]
所以我們只需要計算arr
。
首先,我們創建哈希
ff = f["server"].each_with_object({}) { |g,h| h[g["hostname"]] = g }
#=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}, "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
我們有
enum = f["server"].each_with_object({})
#=> #<Enumerator: [{"hostname"=>"a1", "ip"=>"10"},
# {"hostname"=>"b1", "ip"=>"10.1"}]:each_with_object({})>
我們可以通過將它轉換為數組來查看由此枚舉器生成的元素(並傳遞給它的塊):
enum.to_a
#=> [[{"hostname"=>"a1", "ip"=>"10"}, {}],
# [{"hostname"=>"b1", "ip"=>"10.1"}, {}]]
注意
enum.each { |g,h| h[g["hostname"]] = g }
#=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"},
# "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
each
傳遞enum
的第一個元素並使用並行分配 (也稱為多個賦值 ) 分配塊變量:
g,h = enum.next
#=> [{"hostname"=>"a1", "ip"=>"10"}, {}]
g #=> {"hostname"=>"a1", "ip"=>"10"}
h #=> {}
我們現在可以執行塊計算:
h[g["hostname"]] = g
#=> h["a1"] = {"hostname"=>"a1", "ip"=>"10"}
#=> {"hostname"=>"a1", "ip"=>"10"}
返回值是塊變量h
的新值。 然后將enum
的第二個元素傳遞給塊並執行塊計算:
g,h = enum.next
#=> [{"hostname"=>"b1", "ip"=>"10.1"}, {"a1"=>{"hostname"=>"a1", "ip"=>"10"}}]
g #=> {"hostname"=>"b1", "ip"=>"10.1"}
h #=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}}
請注意,哈希h
已更新。
h[g["hostname"]] = g
#=> {"hostname"=>"b1", "ip"=>"10.1"}
所以現在
h #=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"},
# "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
和
ff #=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}, "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
現在我們可以計算arr
:
g["admin"].map { |h| h.merge(ff[h["hostname"]]) }
g [“admin”]的第一個元素被傳遞給塊並分配給塊變量:
h = g["admin"][0]
#=> {"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}
並執行塊計算:
h.merge(ff[h["hostname"]])
#=> h.merge(ff["a1"])
#=> h.merge({"hostname"=>"a1", "ip"=>"10"})
#=> {"name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10"}
然后
h = g["admin"][1]
#=> {"name"=>"mike", "mail"=>"id", "hostname"=>"b1"}
h.merge(ff[h["hostname"]])
#=> h.merge(ff["b1"])
#=> h.merge({"hostname"=>"a2", "ip"=>"10"})
#=> {"name"=>"mike", "mail"=>"id", "hostname"=>"a2", "ip"=>"10"}
因此,
arr
#=> [{"name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10"},
#=> {"name"=>"mike", "mail"=>"id", "hostname"=>"b1", "ip"=>"10.1"}]
塊返回,我們完成了。
作為另一種變體,你可以試試這個
h1 = { "server" => [{"hostname"=>"a1", "ip"=>"10"}, {"hostname"=>"b1", "ip"=>"10.1"}]}
h2 = { "admin" => [{"name" =>"adam", "mail"=>"any", "hostname"=>"a1"}, {"name" =>"mike", "mail"=>"id", "hostname"=>"b1"}]}
h1['server'].zip(h2['admin']).map { |ar| ar.first.merge(ar.last) }
#=> [{"hostname"=>"a1", "ip"=>"10", "name"=>"adam", "mail"=>"any"}, {"hostname"=>"b1", "ip"=>"10.1", "name"=>"mike", "mail"=>"id"}]
zip
讓我們同時遍歷兩個或更多數組。
我們用map
來返回結果。
在map
塊ar
將等於
[{"hostname"=>"a1", "ip"=>"10"}, {"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}]
[{"hostname"=>"b1", "ip"=>"10.1"}, {"name"=>"mike", "mail"=>"id", "hostname"=>"b1"}]
所以ar.first
將是{"hostname"=>"a1", "ip"=>"10"}
,而ar.last
將是{"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}
最后我們使用merge
來組合兩個哈希。
希望這會有所幫助。
f = { "server"=>[{ "hostname"=>"a1", "ip"=>"10" },
{"hostname"=>"b1", "ip"=>"10.1" }] }
g = { "admin" =>[{ "name"=>"adam", "mail"=>"any", "hostname"=>"a1" },
{ "name"=>"mike", "mail"=>"id", "hostname"=>"b1"}]}
# manual way
host_admin_merge = []
host_admin_merge << f["server"].first.merge(g["admin"].first)
host_admin_merge << f["server"].last.merge(g["admin"].last)
# a bit more automated, iterate, test key's value, append to new array
host_admin_merge = []
f["server"].each do |host|
g["admin"].each do |admin|
if admin[:hostname] == host[:hostname]
host_admin_merge << host.merge(admin)
end
end
end
# assign the array to a hash with "data" as the key
host_admin_hash = {}
host_admin_hash["data"] = host_admin_merge
p host_admin_hash
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.