Find key/value pairs deep inside a hash containing

2019-01-11 02:59发布

A web service is returning a hash that contains an unknown number of nested hashes, some of which contain an array, which in turn contains an unknown number of nested hashes.

Some of the keys are not unique -- i.e. are present in more than one of the nested hashes.

However, all the keys that I actually care about are all unique.

Is there someway I can give a key to the top-level hash, and get back it's value even if the key-value pair is buried deep in this morass?

(The web service is Amazon Product Advertising API, which slightly varies the structure of the results that it gives depending on the number of results and the search types permitted in each product category.)

9条回答
Fickle 薄情
2楼-- · 2019-01-11 03:32

Despite this appearing to be a common problem, I've just spent a while trying to find/come up with exactly what I need, which I think is the same as your requirement. Neither of the links in the first response are spot-on.

class Hash
  def deep_find(key)
    key?(key) ? self[key] : self.values.inject(nil) {|memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
  end
end

So given:

hash = {:get_transaction_list_response => { :get_transaction_list_return => { :transaction => [ { ... 

The following:

hash.deep_find(:transaction)

will find the array associated with the :transaction key.

This is not optimal as the inject will continue to iterate even if memo is populated.

查看更多
Melony?
3楼-- · 2019-01-11 03:32

I use the following code

def search_hash(hash, key)
  return hash[key] if hash.assoc(key)
  hash.delete_if{|key, value| value.class != Hash}
  new_hash = Hash.new
  hash.each_value {|values| new_hash.merge!(values)}
  unless new_hash.empty?
    search_hash(new_hash, key)
  end
end
查看更多
时光不老,我们不散
4楼-- · 2019-01-11 03:37

I ended up using this for a small trie search I wrote:

def trie_search(str, obj=self)
  if str.length <= 1
    obj[str]
  else
    str_array = str.chars
    next_trie = obj[str_array.shift]
    next_trie ? trie_search(str_array.join, next_trie) : nil
  end
end

Note: this is just for nested hashes at the moment. Currently no array support.

查看更多
登录 后发表回答