Traversing a Hash Recursively in Ruby

后端 未结 1 2013
自闭症患者
自闭症患者 2020-12-10 08:43

I\'m having a problem with this function that traverses a Hash. The Hash may contain an Array of Hashes. I want the method to search for an id and then return just the neste

相关标签:
1条回答
  • 2020-12-10 09:11

    When you invoke find_by_id recursively, you're not doing anything with the return value. You need to check whether it found something and if so return that, i.e.:

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

    You also need to return nil at the end of the method (after the each loop), so it returns nil if nothing was found. If you don't, it'll return the return value of each which is the hash that you iterated over.

    Edit:

    Here's the full code with the changes I outlined:

    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
    

    Edit2:

    An alternative approach, that I find cleaner, is to separate the logic for iterating the structure from the logic for finding the element with the right 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
    

    By making dfs return an Enumerable we can use the Enumerable#find method, which makes the code a bit simpler.

    This also enables code reuse if you ever need to write another method that needs to iterate through the hash recursively, as you can just reuse the dfs method.

    0 讨论(0)
提交回复
热议问题