如何在Ruby中深入搜索哈希

时间:2014-10-31 15:33:44

标签: ruby arrays hash

我有一个包含哈希和数组的密钥,我想将此值搜索到从Web应用程序获取的结果中。

  

例如:search_key = {search:[{user:[:first_name,{address:[:state,   :city,:zip]}]},:count],search2:[:location]}

Search_key可以包含任何键和值。这里的key不是静态的,它创建动态,因此它可以是任何。

db_data = {
       search{ 
          user: {
            first_name: "Test user",
            address: {
              street: "main street",
              state: nil,
              city: "Delhi",
              zip: "12345"
            },
          },
          count: 55
          test: 123
        },
        search2:{
          location: "main_data"
          mobile_no: '9998887776'
        }
       }

我需要使用以下密钥来获取检查数据是否存在:

  

search_key = {search:[{user:[:first_name,{address:[:state,:city,   :zip]}]},:count],search2:[:location]}

这里search_key表示:

db_data[:search]
db_data[:search][:user]
db_data[:search][:user][:first_name]
db_data[:search][:user][:address]
db_data[:search][:user][:address][:state]
db_data[:search][:user][:address][:city]
db_data[:search][:user][:address][:zip]
db_data[:search][:count]
db_data[:search2]
db_data[:search2][:location]
  

**注意:: search_key不是静态的。 search_key的键将始终更改,search_key可以是任何类型,如数组的哈希,数组的   哈希值。数组数组,哈希哈希哈希

我需要检查所有密钥是否存在,如果其中一个密钥是nil那么它应该返回false

db_data中的

db_data [:search] [:user] [:address] [:state]为nil然后该函数应返回false。

如果值存在于db_data [:search] [:user] [:address] [:state]中,则该函数应返回true。

[编辑]:

我尝试过这个功能

def data_present?(data, keys)
  keys.each do |k,v|
    return false if data[k].nil?
    if v.is_a?  Array
      v.each do |a|
        if a.is_a? Hash
          data_present?(data[k], a) if data[k].is_a?Hash
          return data[k].each{|r| return data_present?(r, v) } if data[k].is_a?Array
        else
          return false if data[k][a].nil?
        end
      end
    end
  end
end

通过

调用
  

data_present?(db_data,search_key)

递归函数调用无法正常工作。请让我知道我在哪里做错了

1 个答案:

答案 0 :(得分:1)

你在找这样的东西吗?

class Hash
  def flatten_to_key_hierarchy(exclude_nils=false)
    deep_key_retrieval(exclude_nils).each_with_object({}) do |h,obj|
      obj.merge!(h)
    end
  end
  def deep_key_retrieval(exclude_nils=false)
    map do |k,v|
      if v.is_a?(Hash) 
        Hash[k,v.deep_key_retrieval]
      else
        k unless v.nil? && exclude_nils
      end
    end.compact
  end
end

这将产生

db_data = {
       :search=>{
         :user=>{
           :first_name=>"Test user", 
           :address=>{
             :street=>"main street", 
             :state=>nil, 
             :city=>"Delhi", 
             :zip=>"12345"}
           }, 
           :count=>55, 
           :test=>123
        }, 
        :search2=>{
          :location=>"main_data", 
          :mobile_no=>"9998887776"
        }
      }
db_data.flatten_to_key_hierarchy
#=>{:search=>[{:user=>[:first_name, {:address=>[:street, :state, :city, :zip]}]},
    :count, :test], :search2=>[:location, :mobile_no]}

就像我说的那样,我不确定我完全理解你在寻找什么,但这似乎符合你的预期结果。

看到你更新了你的问题。尝试将此添加到上面的

def data_present?(input={},valid_object={},exclude_nils=false)
   input = input.flatten_to_key_hierarchy(exclude_nils)
   validate_against_keys(input,valid_object)
end
private
  def validate_against_keys(input={},valid_object={})
    valid_object.each do |k,v|
      return false unless input.has_key?(k) && input[k].class == v.class
      if v.is_a?(Hash)
        validate_against_keys(input[k],v)
      elsif v.is_a?(Array)
        return false unless v - input[k] == []
      end
    end
    true
  end

#data_present?会将您的原始db_data作为输入,将已确定的结构作为valid_object。它将忽略db_data中的其他键,仅查找test_data

中指定的键
test_data =  db_data.flatten_to_key_hierarchy
data_present?(db_data,test_data,true)
#=> true
test_data[:search].delete(:test)
data_present?(db_data,test_data,true)
#=> true
test_data[:search] << :something_else
data_present?(db_data,test_data,true)
#=> false