在 Ruby 中递归遍历哈希 [英] Traversing a Hash Recursively in Ruby

查看:44
本文介绍了在 Ruby 中递归遍历哈希的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 nested hash it finds.

似乎对遍历有效,但返回的是传入的原始值.

It seems to work for the traversal, but it returns the original value passed in.

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')

推荐答案

当您递归调用 find_by_id 时,您不会对返回值执行任何操作.您需要检查它是否找到了某些东西,如果是,则返回,即:

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

您还需要在方法的末尾(在每个循环之后)返回 nil,因此如果没有找到任何内容,它将返回 nil.如果不这样做,它将返回 each 的返回值,这是您迭代的哈希值.

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.

这是包含我概述的更改的完整代码:

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

编辑 2:

我认为更简洁的另一种方法是将用于迭代结构的逻辑与用于查找具有正确 id 的元素的逻辑分开:

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

通过让 dfs 返回一个 Enumerable,我们可以使用 Enumerable#find 方法,这使得代码更简单一些.

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

如果您需要编写另一个需要递归遍历哈希的方法,这也可以实现代码重用,因为您可以重用 dfs 方法.

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.

这篇关于在 Ruby 中递归遍历哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆