如果值递归地包含字符串,则Ruby返回顶级散列键

我有下面的数据结构,我试图返回顶级键(lo,eth0或eth1),如果在任何地方递归和任意深度,它的值是给定的字符串。 然后在找到第一个字符串实例后终止搜索。

在包含任意数量的嵌套哈希和数组的哈希深处查找键/值对这类似于我想要做的但我无法将其映射到我自己的问题

h.find{ |k,v| break k if v.include? "number" } => "eth0" h.find{ |k,v| break k if v.include? "10.0.128.26" } => nil #Should return eth0 

我想知道如何通常使用这样的嵌套数据结构,但我决定能够在特定的子哈希,我的情况下的地址中专门搜索。

  h = \ {"lo"=> {"mtu"=>"65536", "flags"=>["LOOPBACK", "UP", "LOWER_UP"], "encapsulation"=>"Loopback", "addresses"=> {"127.0.0.1"=> {"family"=>"inet", "prefixlen"=>"8", "netmask"=>"255.0.0.0", "scope"=>"Node"}}, "state"=>"unknown"}, "eth0"=> {"type"=>"eth", "number"=>"0", "mtu"=>"1500", "flags"=>["BROADCAST", "MULTICAST", "UP", "LOWER_UP"], "encapsulation"=>"Ethernet", "addresses"=> {"00:0C:29:1A:64:6A"=>{"family"=>"lladdr"}, "10.0.128.26"=> {"family"=>"inet", "prefixlen"=>"24", "netmask"=>"255.255.255.0", "broadcast"=>"10.0.128.255", "scope"=>"Global"}}, "state"=>"up", "arp"=> {"10.0.128.31"=>"00:0c:29:04:12:9a", "10.0.128.100"=>"00:0c:29:5b:b4:46", "10.0.128.30"=>"00:0c:29:05:a4:c7", "10.0.128.18"=>"00:0c:29:6a:3f:75", "10.0.128.3"=>"0c:c4:7a:c0:31:d1", "10.0.128.43"=>"00:0c:29:01:eb:6b", "10.0.128.44"=>"00:09:0f:09:00:03", "10.0.128.14"=>"00:0c:29:d2:15:80", "10.0.128.22"=>"00:0c:29:18:99:30"}, "routes"=> [{"destination"=>"10.0.128.0/24", "family"=>"inet", "scope"=>"link", "proto"=>"kernel", "src"=>"10.0.128.26"}], "link_speed"=>10000, "duplex"=>"Full", "port"=>"Twisted Pair", "transceiver"=>"internal", "auto_negotiation"=>"off", "mdi_x"=>"Unknown", "ring_params"=> {"max_rx"=>4096, "max_rx_mini"=>0, "max_rx_jumbo"=>2048, "max_tx"=>4096, "current_rx"=>256, "current_rx_mini"=>0, "current_rx_jumbo"=>128, "current_tx"=>512}}, "eth1"=> {"type"=>"eth", "number"=>"1", "mtu"=>"1500", "flags"=>["BROADCAST", "MULTICAST", "UP", "LOWER_UP"], "encapsulation"=>"Ethernet", "addresses"=> {"00:0C:29:1A:64:74"=>{"family"=>"lladdr"}, "11.11.11.1"=> {"family"=>"inet", "prefixlen"=>"24", "netmask"=>"255.255.255.0", "broadcast"=>"11.11.11.1", "scope"=>"Global"}}, "state"=>"up", "routes"=> [{"destination"=>"default", "family"=>"inet", "via"=>"11.11.11.1"}, {"destination"=>"11.11.11.1/24", "family"=>"inet", "scope"=>"link", "proto"=>"kernel", "src"=>"11.11.11.1"}], "link_speed"=>10000, "duplex"=>"Full", "port"=>"Twisted Pair", "transceiver"=>"internal", "auto_negotiation"=>"off", "mdi_x"=>"Unknown", "ring_params"=> {"max_rx"=>4096, "max_rx_mini"=>0, "max_rx_jumbo"=>2048, "max_tx"=>4096, "current_rx"=>256, "current_rx_mini"=>0, "current_rx_jumbo"=>128, "current_tx"=>512}}} 

当您想要返回顶部父键时,您可以使用提到的答案以及find顶部哈希键以一种简单的方式执行此操作

 #return true if find or nil def deep_key?(obj, key) if obj.respond_to?(:key?) && obj.key?(key) true elsif obj.respond_to?(:each) r = nil obj.find{ |*a| r = deep_key?(a.last, key) } r end end key = '00:0C:29:1A:64:74' #now you check if the provided key is a top level key or run search h.key?(key) ? key : h.find { |k, v| deep_key?(v, key) }.first 

deep_key? 它是来自上述答案的一点修改后的搜索function,如果找到一个键则返回true如果找不到则返回nil )。 你可以在Hash#find block – top-level key中使用这个函数,如果找到它,它的值将是结果( first添加只返回一个键)。

由于您对顶级密钥感兴趣,您可以执行以下操作:

 hash.find{ |k,v| break k if v.to_s.include? "10.0.128.26" } #=> eth0 

通过使用v.to_s ,我们能够搜索散列的字符串表示,并且还能够避免递归。