如果值递归包含字符串,Ruby 返回***哈希键

Posted

技术标签:

【中文标题】如果值递归包含字符串,Ruby 返回***哈希键【英文标题】:Ruby return top level hash key if value recursively contains string 【发布时间】:2017-10-02 01:23:47 【问题描述】:

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

Find key/value pairs deep inside a hash containing an arbitrary number of nested hashes and arrays 这有点类似于我正在尝试做的事情,但我无法将其映射到我自己的问题

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

【问题讨论】:

请更正您的示例。 (它突然结束。)如果您不提供有效的对象,读者将无法测试他们的代码。当您使用它时,请为您的哈希分配一个变量(例如,h = "lo"=>...),以便读者可以在他们的答案和 cmets 中引用该变量而无需定义它。 完成。感谢您的评论 【参考方案1】:

由于您对***密钥感兴趣,您可以这样做:

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

通过使用v.to_s,我们可以在哈希的字符串表示中进行搜索,也可以避免递归。

【讨论】:

仅仅把整个东西变成一个字符串对于这种特殊情况可能会很好。但我仍然想知道如何“正确”搜索这样的嵌套哈希【参考方案2】:

如果您想返回***父键,您可以使用***哈希键的 mentioned answer 和 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? 是对上述答案的一点修改的搜索功能,如果找到一个键,则返回 true(如果没有找到,则返回 nil)。您可以在 Hash#find 块内使用此函数 - ***键,如果找到他的值将是结果(添加 first 只返回一个键)。

【讨论】:

你能解释一下你最后一行的语法吗?我很难理解 find 语句之前的部分。

以上是关于如果值递归包含字符串,Ruby 返回***哈希键的主要内容,如果未能解决你的问题,请参考以下文章

如何递归检查ruby hash成员是不是存在?

为啥关键字参数必须作为带有符号键的哈希传递,而不是 Ruby 中的字符串键?

Ruby - 按值按降序排序哈希值

在Ruby中将嵌套哈希键从CamelCase转换为snake_case

ruby 哈希包含另一个哈希,深度检查

ruby 将哈希值转换为排序的字符串数组,以便与另一个哈希值进行比较