代码之家  ›  专栏  ›  技术社区  ›  Dex

在Ruby中递归遍历散列

  •  4
  • Dex  · 技术社区  · 16 年前

    我对这个遍历散列的函数有问题。哈希可以包含哈希数组。我希望该方法搜索一个id,然后只返回它找到的嵌套哈希。

    它似乎适用于遍历,但它返回传入的原始值。

    require 'rubygems'
    require 'ruby-debug'
    
    def find_by_id(node, find_this="")
      if node.is_a?(Hash)
        node.each do |k,v|
          if v.is_a?(Array)
            v.each do |elm|
              if elm["_id"] == find_this && !find_this.empty?
                return elm      # THIS IS WHAT I WANT!
              else
                find_by_id(elm, find_this)
              end
            end
          end
        end
      end
    end
    
    x = {"name" => "first", "_id"=>'4c96a9a56f831b0eb9000005', "items"=>["name" => "second", "_id"=>'4c96a9af6f831b0eb9000009', "others"=>[{"name" => "third", "_id"=>'4c96a9af6f831b0eb9000007'}, {"name" => "fourth", "_id"=>'4c96a9af6f831b0eb9000008'}] ] }
    
    find_by_id(x, '4c96a9af6f831b0eb9000008')
    
    1 回复  |  直到 16 年前
        1
  •  12
  •   sepp2k    16 年前

    当你调用 find_by_id 递归地,您不会对返回值做任何操作。你需要检查它是否发现了什么东西,如果是的话,把它还回去,即:

    result = find_by_id(elm, find_this)
    return result if result
    

    你也需要回来 nil 在方法的末尾(在每个循环之后),因此它返回 如果什么都没找到。否则,它将返回 each 这是你迭代过的散列。

    编辑:

    以下是我概述的更改的完整代码:

    def find_by_id(node, find_this="")
      if node.is_a?(Hash)
        node.each do |k,v|
          if v.is_a?(Array)
            v.each do |elm|
              if elm["_id"] == find_this && !find_this.empty?
                return elm      # THIS IS WHAT I WANT!
              else
                result = find_by_id(elm, find_this)
                return result if result
              end
            end
          end
        end
      end
      # Return nil if no match was found
      nil
    end
    

    编辑2:

    另一种方法,我发现更干净,是将用于迭代结构的逻辑与用于查找具有正确id的元素的逻辑分开:

    def dfs(hsh, &blk)
      return enum_for(:dfs, hsh) unless blk
    
      yield hsh
      hsh.each do |k,v|
        if v.is_a? Array
          v.each do |elm|
            dfs(elm, &blk)
          end
        end
      end
    end
    
    def find_by_id(hsh, search_for)
      dfs(hsh).find {|node| node["_id"] == search_for }
    end
    

    通过制造 dfs 返回 Enumerable 我们可以使用 Enumerable#find 方法,使代码更简单。

    如果您需要编写另一个需要递归地遍历散列的方法,这也支持代码重用,因为您可以重用dfs方法。

    推荐文章