[英]How to merge two arrays of hashes by the same pair of key and value ruby
I'm new in ruby. 我是红宝石的新手。 I have two hashes:
我有两个哈希:
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"}]}
and I want to get another hash like this: 我想得到另一个像这样的哈希:
{ "data" => [{"hostname"=>"a1", "ip"=>"10", "name" =>"adam", "mail"=>"any"},
{"hostname"=>"b1", "ip"=>"10.1", "name" =>"mike", "mail"=>"id"}]}
The pairs "hostname"=>"something"
always matches in hashes of both arrays. 对
"hostname"=>"something"
总是匹配两个数组的哈希值。 I have tried something like this: 我试过这样的事情:
data = server.merge(admin)
but it isn't so easy and as you expect it doesn't work. 但它并不容易,因为你认为它不起作用。 Could you help me merge these hashes and explain for the future how you did it?
你能帮我合并这些哈希并解释你未来的表现吗?
A quick way that i can think of right now will look like: 我现在能想到的一种快速方式如下:
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"}]
Code and example 代码和示例
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"}]}
Explanation 说明
We want to produce a hash 我们想要产生一个哈希
{ "data"=>arr }
where 哪里
arr #=> [{ "name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10" },
# { "name"=>"mike", "mail"=>"id", "hostname"=>"b1", "ip"=>"10.1" }]
so we need only compute arr
. 所以我们只需要计算
arr
。
First, we create the hash 首先,我们创建哈希
ff = f["server"].each_with_object({}) { |g,h| h[g["hostname"]] = g }
#=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}, "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
We have 我们有
enum = f["server"].each_with_object({})
#=> #<Enumerator: [{"hostname"=>"a1", "ip"=>"10"},
# {"hostname"=>"b1", "ip"=>"10.1"}]:each_with_object({})>
We can see the elements that will be generated by this enumerator (and passed to its block) by converting it to an array: 我们可以通过将它转换为数组来查看由此枚举器生成的元素(并传递给它的块):
enum.to_a
#=> [[{"hostname"=>"a1", "ip"=>"10"}, {}],
# [{"hostname"=>"b1", "ip"=>"10.1"}, {}]]
Note 注意
enum.each { |g,h| h[g["hostname"]] = g }
#=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"},
# "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
each
passes the first element of enum
and assigns the block variables using parallel assignement (also call multiple assignment ): each
传递enum
的第一个元素并使用并行分配 (也称为多个赋值 ) 分配块变量:
g,h = enum.next
#=> [{"hostname"=>"a1", "ip"=>"10"}, {}]
g #=> {"hostname"=>"a1", "ip"=>"10"}
h #=> {}
We may now perform the block calculation: 我们现在可以执行块计算:
h[g["hostname"]] = g
#=> h["a1"] = {"hostname"=>"a1", "ip"=>"10"}
#=> {"hostname"=>"a1", "ip"=>"10"}
The return value is the new value of the block variable h
. 返回值是块变量
h
的新值。 The second element of enum
is then passed to the block and the block calculation is performed: 然后将
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"}}
Notice that the hash h
has been updated. 请注意,哈希
h
已更新。
h[g["hostname"]] = g
#=> {"hostname"=>"b1", "ip"=>"10.1"}
So now 所以现在
h #=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"},
# "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
and 和
ff #=> {"a1"=>{"hostname"=>"a1", "ip"=>"10"}, "b1"=>{"hostname"=>"b1", "ip"=>"10.1"}}
Now we can compute arr
: 现在我们可以计算
arr
:
g["admin"].map { |h| h.merge(ff[h["hostname"]]) }
The first element of g["admin"] is passed to the block and assigned to the block variable: g [“admin”]的第一个元素被传递给块并分配给块变量:
h = g["admin"][0]
#=> {"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}
and the block calculation is performed: 并执行块计算:
h.merge(ff[h["hostname"]])
#=> h.merge(ff["a1"])
#=> h.merge({"hostname"=>"a1", "ip"=>"10"})
#=> {"name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10"}
Then 然后
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"}
Therefore, 因此,
arr
#=> [{"name"=>"adam", "mail"=>"any", "hostname"=>"a1", "ip"=>"10"},
#=> {"name"=>"mike", "mail"=>"id", "hostname"=>"b1", "ip"=>"10.1"}]
is returned by the block and we are finished. 块返回,我们完成了。
As another variant you can try this 作为另一种变体,你可以试试这个
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
let us iterate through two or more arrays at the same time. zip
让我们同时遍历两个或更多数组。
We use map
to return result. 我们用
map
来返回结果。
In map
block ar
would be equal 在
map
块ar
将等于
[{"hostname"=>"a1", "ip"=>"10"}, {"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}]
[{"hostname"=>"b1", "ip"=>"10.1"}, {"name"=>"mike", "mail"=>"id", "hostname"=>"b1"}]
So ar.first
would be {"hostname"=>"a1", "ip"=>"10"}
and the ar.last
would be {"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}
所以
ar.first
将是{"hostname"=>"a1", "ip"=>"10"}
,而ar.last
将是{"name"=>"adam", "mail"=>"any", "hostname"=>"a1"}
Finally we use merge
to combine two hashes. 最后我们使用
merge
来组合两个哈希。
Hope this will help. 希望这会有所帮助。
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.