繁体   English   中英

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

[英]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来返回结果。

mapar将等于

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

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