Web服務正在返回包含未知數量嵌套哈希的哈希,其中一些包含數組,其中包含未知數嵌套散列的數量。在包含任意數量的嵌套散列和數組的哈希中深入查找鍵/值對
某些鍵不是唯一的 - 即存在於多於一個嵌套散列中。
但是,我真正關心的所有密鑰都是獨一無二的。
是否有某種方式可以給頂層散列鍵一個鍵,並且即使鍵值對深埋在這個泥潭中也能找回它的值?
(Web服務是亞馬遜商品廣告API,它略有不同的結果,這取決於結果在各個產品類別允許的搜索類型的數量,並給出了結構。)
Web服務正在返回包含未知數量嵌套哈希的哈希,其中一些包含數組,其中包含未知數嵌套散列的數量。在包含任意數量的嵌套散列和數組的哈希中深入查找鍵/值對
某些鍵不是唯一的 - 即存在於多於一個嵌套散列中。
但是,我真正關心的所有密鑰都是獨一無二的。
是否有某種方式可以給頂層散列鍵一個鍵,並且即使鍵值對深埋在這個泥潭中也能找回它的值?
(Web服務是亞馬遜商品廣告API,它略有不同的結果,這取決於結果在各個產品類別允許的搜索類型的數量,並給出了結構。)
這裏有一個簡單的遞歸解決方案:
def nested_hash_value(obj,key)
if obj.respond_to?(:key?) && obj.key?(key)
obj[key]
elsif obj.respond_to?(:each)
r = nil
obj.find{ |*a| r=nested_hash_value(a.last,key) }
r
end
end
h = { foo:[1,2,[3,4],{a:{bar:42}}] }
p nested_hash_value(h,:bar)
#=> 42
此代碼導致堆棧溢出。我想這是由於字符串和/或其他會響應每個方法的東西。我將'elsif obj.respond_to?(:each)'改爲'elsif obj.is_a?(Hash)或obj.is_a?(Array)'。現在它工作正常。感謝您的解決方案。 – Vigneshwaran
如果這個東西打印出它的路徑(麪包屑?),它會很好...... –
如果有多個哈希包含:bar key會怎樣,如果我們想要每個值的數組,它會是什麼樣的解決方案:酒吧鑰匙? – RSB
儘管看似是一個常見的問題,我剛剛花了一段時間試圖找到/拿出正是我需要的,我認爲這是與您的需求。第一個響應中的鏈接都沒有發現。
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
所以給出:
hash = {:get_transaction_list_response => { :get_transaction_list_return => { :transaction => [ { ...
以下:
hash.deep_find(:transaction)
會發現相關的數組:交易的關鍵。
這不是最佳的,因爲即使填充了備忘錄,注入也會繼續進行迭代。
結合一些上述問題的答案和評論:
class Hash
def deep_find(key, object=self, found=nil)
if object.respond_to?(:key?) && object.key?(key)
return object[key]
elsif object.is_a? Enumerable
object.find { |*a| found = deep_find(key, a.last) }
return found
end
end
end
我用下面的代碼
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
最後我用這一個小線索搜索我寫道:
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
注意:這只是當前嵌套散列。目前沒有陣列支持。
無需猴子修補,只需使用HASHIE寶石:https://github.com/intridea/hashie#deepfind
user = {
name: { first: 'Bob', last: 'Boberts' },
groups: [
{ name: 'Rubyists' },
{ name: 'Open source enthusiasts' }
]
}
user.extend Hashie::Extensions::DeepFind
user.deep_find(:name) #=> { first: 'Bob', last: 'Boberts' }
任意可枚舉的對象,還有一個伸展的,DeepLocate:https://github.com/intridea/hashie#deeplocate
爲什麼這會被標記下來? –
我發現Hashi :: Extensions :: DeepFind是一個很好的方法。如果您正在尋找重複的密鑰,那麼deep_find_all()方法非常棒。強烈推薦。 – JESii
barelyknown的解決方案的一個變化:這會找到密鑰中的所有值都是散列值而不是第一個匹配值。
class Hash
def deep_find(key, object=self, found=[])
if object.respond_to?(:key?) && object.key?(key)
found << object[key]
end
if object.is_a? Enumerable
found << object.collect { |*a| deep_find(key, a.last) }
end
found.flatten.compact
end
end
{a: [{b: 1}, {b: 2}]}.deep_find(:b)
將返回[1, 2]
由於Rails ActionController的5 ::參數不再哈希繼承,我不得不改變方法,使其對特定參數。
module ActionController
class Parameters
def deep_find(key, object=self, found=nil)
if object.respond_to?(:key?) && object.key?(key)
return object[key]
elsif object.respond_to?(:each)
object = object.to_unsafe_h if object.is_a?(ActionController::Parameters)
object.find { |*a| found = deep_find(key, a.last) }
return found
end
end
end
end
如果找到了鍵,返回鍵的值,但不會返回的ActionController :: Parameter對象如此強大的參數不保留。
不適用於多個參數鍵: {0:[{b:'1'}],1:[{b:'2'}]} .deep_find(:b) return: #>'1 「 – m1l05z
這個問題出現了很多,像[這裏](http://stackoverflow.com/questions/1820451/ruby-style-how-to-check-whether-a-nested-hash-element-exists)和[這裏](http://stackoverflow.com/questions/7139471/transform-a-ruby-hash-into-a-dotted-path-key-string)等等。 –
如果您可以創建一些示例數據來顯示您遇到的情況,它總是有幫助的,所以我們不必去想象。另外,數據如何發送?你收到XML並解析它嗎? JSON?或者,您是否正在使用返回神祕結構的電話,而其他所有電話都是黑匣子? –