简体   繁体   English

如何通过同一对键和值ruby合并两个哈希数组

[英]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 mapar将等于

  • [{"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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM