简体   繁体   English

Ruby合并哈希键值

[英]Ruby Merge Hash Key Value

I have two hashes: one containing a list of hosts and another with network data. 我有两个哈希值:一个包含主机列表,另一个包含网络数据。 I want to create a third hash that combines the host data with the network data. 我想创建将主机数据与网络数据结合在一起的第三个哈希。

Here's an example of the two hashes: 这是两个哈希的示例:

{
   :myhost1=>{:name=>"hostname1", :trust=>:net80, :dmz=>:net81},
   :myhost2=>{:name=>"anotherhost", :trust=>:net80, :dmz=>:net82}
}

{
   :net80=>{:range=>"192.168.0.0", :gateway=>"192.168.0.1", :netmask=>"255.255.255.0"}, 
   :net81=>{:range=>"192.168.1.0", :gateway=>"192.168.1.1", :netmask=>"255.255.255.0"}, 
   :net82=>{:range=>"192.168.3.0", :gateway=>"192.168.2.1", :netmask=>"255.255.248.0"}
}

The merge would be with trust and dmz - replacing the key in the host info with the value of the associated key in the network info. 合并将使用trust和dmz-用网络信息中关联密钥的值替换主机信息中的密钥。 The merged hash would be this: 合并的哈希将是这样的:

{
   :myhost1=>{:name=>"hostname1", :trust=>{:range=>"192.168.0.0", :gateway=>"192.168.0.1", :netmask=>"255.255.255.0"}, :dmz=>{:range=>"192.168.1.0", :gateway=>"192.168.1.1", :netmask=>"255.255.255.0"}}, 
   :myhost2=>{:name=>"anotherhost", :trust=>{:range=>"192.168.0.0", :gateway=>"192.168.0.1", :netmask=>"255.255.255.0"}, :dmz=>{:range=>"192.168.3.0", :gateway=>"192.168.2.1", :netmask=>"255.255.248.0"}}
}

EDIT: I've updatd the host hash to use symbols to make the merge easier. 编辑:我已经更新主机哈希值,以使用符号使合并更加容易。

The idea here is you can convert the initial structure by expanding certain keys, or not expanding others depending on the overall shape of that thing. 这里的想法是,您可以通过扩展某些键来转换初始结构,也可以不扩展其他键,这取决于事物的整体形状。 Here's an example: 这是一个例子:

hosts = {
   myhost1: {:name=>"hostname1", :trust=>"net80", :dmz=>"net81"},
   myhost2: {:name=>"anotherhost", :trust=>"net80", :dmz=>"net82"}
}

nets = {
   net80: {:range=>"192.168.0.0", :gateway=>"192.168.0.1", :netmask=>"255.255.255.0"}, 
   net81: {:range=>"192.168.1.0", :gateway=>"192.168.1.1", :netmask=>"255.255.255.0"}, 
   net82: {:range=>"192.168.3.0", :gateway=>"192.168.2.1", :netmask=>"255.255.248.0"}
}

hosts.collect do |name, entry|
  [
    name,
    entry.map do |key, value|
      case (key)
      when :name
        [ key, value ]
      else
        [ key, nets[value.to_sym] ]
      end
    end.to_h
  ]
end

# => {:myhost1=>{:name=>"hostname1", :trust=>{:range=>"192.168.0.0", ...

This would be marginally less messy if you had trust: :net80 to keep symbol-symbol matching. 如果您trust: :net80来保持符号-符号匹配,那么这将稍微减少混乱。

hosts = {
  :myhost1=>{ :name=>"hostname1",   :trust=>:net80, :dmz=>:net81 },
  :myhost2=>{ :name=>"anotherhost", :trust=>:net80, :dmz=>:net82 }
}

network = {
  :net80=>{ :range=>"192.168.0.0", :gateway=>"192.168.0.1",
            :netmask=>"255.255.255.0" }, 
  :net81=>{ :range=>"192.168.1.0", :gateway=>"192.168.1.1",
            :netmask=>"255.255.255.0" }, 
  :net82=>{ :range=>"192.168.3.0", :gateway=>"192.168.2.1",
            :netmask=>"255.255.248.0" }
}

Here are two approaches that could be used. 这是可以使用的两种方法。

#1 Merge the hash with itself, changing some values #1将散列与其自身合并,更改一些值

hosts.merge(hosts) { |*,g|
  g.merge(trust: network[g[:trust]], dmz: network[g[:dmz]]) }
  #=> {
  #     :myhost1=>{
  #       :name =>"hostname1",
  #       :trust=>{ :range=>"192.168.0.0", :gateway=>"192.168.0.1",
  #                 :netmask=>"255.255.255.0" },
  #       :dmz  =>{ :range=>"192.168.1.0", :gateway=>"192.168.1.1",
  #                 :netmask=>"255.255.255.0" }
  #     }, 
  #     :myhost2=>{
  #       :name =>"anotherhost",
  #       :trust=>{ :range=>"192.168.0.0", :gateway=>"192.168.0.1",
  #                 :netmask=>"255.255.255.0" },
  #       :dmz  =>{ :range=>"192.168.3.0", :gateway=>"192.168.2.1",
  #                 :netmask=>"255.255.248.0" }
  #     }
  #   }

#2 Build a hash #2建立哈希

hosts.each_with_object({}) { |(host,g), h|
  h[host] = { :name =>g[:name],
              :trust=>network[g[:trust]],
              :dmz  =>network[g[:dmz]] } }
  #=> same as for #1

Try this 尝试这个

hosts.each_value do |hash| 
  hash[:trust] = nets[hash[:trust]]
  hash[:dmz] = nets[hash[:dmz]]
end

NB, this mutates the hosts data structure. 注意,这会改变hosts数据结构。

With Ruby 2.4 long-awaited transform_values , it's possible to design a solution that would work in many other cases : 使用Ruby 2.4期待已久的transform_values ,可以设计一种在许多其他情况下都可以使用的解决方案:

hosts =
  {
    myhost1: { name: 'hostname1', trust: :net80, dmz: :net81 },
    myhost2: { name: 'anotherhost', trust: :net80, dmz: :net82 }
  }

networks = {
  net80: { range: '192.168.0.0', gateway: '192.168.0.1', netmask: '255.255.255.0' },
  net81: { range: '192.168.1.0', gateway: '192.168.1.1', netmask: '255.255.255.0' },
  net82: { range: '192.168.3.0', gateway: '192.168.2.1', netmask: '255.255.248.0' }
}

class Hash
  #{lost: :key}.translate(key: :clef) #=> {:lost=>:clef}
  def translate(dict)
    transform_values do |v|
      if v.is_a?(Hash)
        v.translate(dict)
      elsif dict.key?(v)
        dict[v]
      else
        v
      end
    end
  end
end


require 'pp'
pp hosts.translate(networks)
# {:myhost1=>
#   {:name=>"hostname1",
#    :trust=>
#     {:range=>"192.168.0.0",
#      :gateway=>"192.168.0.1",
#      :netmask=>"255.255.255.0"},
#    :dmz=>
#     {:range=>"192.168.1.0",
#      :gateway=>"192.168.1.1",
#      :netmask=>"255.255.255.0"}},
#  :myhost2=>
#   {:name=>"anotherhost",
#    :trust=>
#     {:range=>"192.168.0.0",
#      :gateway=>"192.168.0.1",
#      :netmask=>"255.255.255.0"},
#    :dmz=>
#     {:range=>"192.168.3.0",
#      :gateway=>"192.168.2.1",
#      :netmask=>"255.255.248.0"}}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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