Ruby Merge哈希键值

时间:2017-01-07 01:23:41

标签: ruby hash

我有两个哈希:一个包含主机列表,另一个包含网络数据。我想创建一个将主机数据与网络数据相结合的第三个哈希。

以下是两个哈希的示例:

{
   :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"}
}

合并将使用trust和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"}}
}

编辑:我已更新主机哈希以使用符号来简化合并。

4 个答案:

答案 0 :(得分:2)

这里的想法是你可以通过扩展某些键来转换初始结构,或者根据该事物的整体形状不扩展其他键。这是一个例子:

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", ...

如果你trust: :net80保持符号 - 符号匹配,那么这将稍微不那么混乱。

答案 1 :(得分:2)

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

以下是两种可以使用的方法。

#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构建哈希

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

答案 2 :(得分:1)

试试这个

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

注意,这会改变hosts数据结构。

答案 3 :(得分:0)

使用期待已久的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"}}}