查找与嵌套红宝石哈希中的参数匹配的所有值

时间:2019-04-18 11:06:57

标签: ruby select hash

如果我有这样的多嵌套哈希值

{
  "Monday"=>{
    "North"=>{
      "Group 1"=>[
        {:name=>"Event A", :type=>"Private"},
        {:name=>"Event B", :type=>"Public"},
      ]
    },
    "South"=>{
      "Group 1"=>[
        {:name=>"Event c", :type=>"Private"},
        {:name=>"Event D", :type=>"Public"},
        {:name=>"Event E", :type=>"Private"},
      ]
    }
  },
  "Tuesday"=>{
    "North"=>{
      "Group 1"=>[
        {:name=>"Event F", :type=>"Private"},
        {:name=>"Event G", :type=>"Public"},
      ]
    },
    "South"=>{
      "Group 1"=>[
        {:name=>"Event H", :type=>"Private"},
      ]
    }
  }
}

我希望能够在哈希中搜索所有type等于Private的事件

在不完全知道哈希中键的值的情况下,我该怎么做?

3 个答案:

答案 0 :(得分:1)

如果使用 gem 是一种选择,则存在iteraptor,这显然是关于迭代深层嵌套的结构。

假设您的原始哈希名为hash,我们开始:

hash.iteraptor.
     each(full_parent: true, yield_all: true).
     with_object({}) do |(parent, (k, v)), acc|
  (acc[parent[0...-1]] ||= []) << k if
    parent.last.is_a?(Integer) && v.nil? && k.is_a?(Hash) && k[:type] == "Private"
end

结果:

#⇒ {["Monday", "North", "Group 1"] =>
#       [{:name=>"Event A", :type=>"Private"}],
#   ["Monday", "South", "Group 1"] =>
#       [{:name=>"Event c", :type=>"Private"},
#        {:name=>"Event E", :type=>"Private"}],
#   ["Tuesday", "North", "Group 1"] =>
#       [{:name=>"Event F", :type=>"Private"}],
#   ["Tuesday", "South", "Group 1"] =>
#       [{:name=>"Event H", :type=>"Private"}]}

答案 1 :(得分:1)

在递归解决此问题时,我做了三个假设:

  • 可以有任意数量的嵌套数组和散列;
  • :type是唯一已知的密钥;
  • 如果哈希包含密钥:type,则它恰好包含另一个密钥。

def get_em(obj)
  arr = []
  case obj
  when Hash
    obj.values.each do |v|
      case v
      when "Private"
        arr += obj.values-[v]
      when Hash, Array
        arr += get_em(v)
      end
    end
  when Array
    obj.each { |e| arr += get_em(e) if Hash === e || Array === e }
  end
  arr
end

如果h是示例中给出的哈希,

get_em(h)
  #=> ["Event A", "Event C", "Event E", "Event F", "Event H"]

注意Hash === e等同于e.is_a?(Hash)

答案 2 :(得分:0)

尝试此递归:

  def hash_match(the_hash)
    found=false
    the_hash.each do |key, value|
      if value.is_a?(Hash)
        if hash_match(value)
          if value.has_key :name
            puts value[:name]
          end
        end
      elsif value.is_a?(Array)
        value.each do |element|
          if element.is_a?(Hash)
            if hash_match(element)
              if element.has_key? :name
                puts element[:name]
              end
            end
          end
        end
      else
        if key==:type && value=="Private"
          found=true
        end
      end
    end
    return found
  end

然后只需致电hash_match(your_hash)