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

时间:2016-06-23 19:29:07

标签: arrays ruby hash 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"}]}

我希望得到另一个这样的哈希:

{ "data" => [{"hostname"=>"a1", "ip"=>"10", "name" =>"adam", "mail"=>"any"},
             {"hostname"=>"b1", "ip"=>"10.1", "name" =>"mike", "mail"=>"id"}]}

"hostname"=>"something"总是匹配两个数组的哈希值。我尝试过这样的事情:

data = server.merge(admin)

但它并不容易,因为你认为它不起作用。你能帮我合并这些哈希并解释你未来的表现吗?

4 个答案:

答案 0 :(得分:0)

我现在想到的一个快速方式如下:

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"}]

答案 1 :(得分:0)

代码和示例

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的第一个元素并使用 parallel assignement 分配块变量(也称为多个赋值):

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 [&#34; admin&#34;]的第一个元素被传递给块并分配给块变量:

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"}] 
块返回

,我们完成了。

答案 2 :(得分:0)

作为另一种变体,你可以尝试这个

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来组合两个哈希值 希望这会有所帮助。

答案 3 :(得分:0)

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