簡體   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