2012-03-13 13 views
1

我有一個嵌套的散列,並希望單個數組,其中每個元素是一個鍵數組,它表示通過嵌套散列到非散列(葉節點)的路徑。收集訪問葉節點的嵌套散列鍵數組的最有效方法是什麼?

例如,給定的輸入:

x = Hash.new 
x["a"] = Hash.new 
x["a"]["b"] = Hash.new 
x["a"]["b"]["c"] = "one" 
x["a"]["b"]["d"] = "two" 
x["a"]["e"] = "three" 
x["f"] = Hash.new 
x["f"]["g"] = "four" 

我想的輸出:

[["a", "b", "c"], ["a", "b", "d"], ["a", "e"], ["f", "g"]] 

下面的代碼使用兩個遞歸方法原理:一個產生一個嵌套陣列,另去嵌套它!

我的Ruby直覺告訴我必須有一個更高效和更優雅的方式來實現這一點。任何人都可以推薦'高爾夫'解決方案,或者完美的Ruby Way解決方案嗎?

def collect_key_paths(object, path=[]) 
    result = nil 
    if object.is_a?(Hash) 
    path_for_current_hash = object.map do |key, value| 
     incremented_path = [path, key].flatten 
     collect_key_paths(value, incremented_path) 
    end 
    result = path_for_current_hash 
    else 
    result = path 
    end 
    result 
end 

def smoothe(array, store=[]) 
    if array.none? { |element| element.is_a?(Array) } 
    store << array 
    else 
    array.each do |element| 
     store = smoothe(element, store) 
    end 
    end 
    store 
end 


x = Hash.new 
x["a"] = Hash.new 
x["a"]["b"] = Hash.new 
x["a"]["b"]["c"] = "one" 
x["a"]["b"]["d"] = "two" 
x["a"]["e"] = "three" 
x["f"] = Hash.new 
x["f"]["g"] = "four" 

nested_key_paths = collect_key_paths(x) 
puts "RESULT:#{smoothe(nested_key_paths)}" 

這段代碼的結果,運行版本1.9.2:

RESULT:[["a", "b", "c"], ["a", "b", "d"], ["a", "e"], ["f", "g"]] 

謝謝!

+0

POS sible將[嵌套哈希轉換爲平面哈希]的副本(http://stackoverflow.com/questions/9647997/converting-a-nested-hash-into-a-flat-hash) – sawa 2012-03-13 13:53:03

+0

您可以先獲得哈希給定在我給出的重複問題中,然後取出'keys'。 – sawa 2012-03-13 13:54:08

回答

0

我不知道這是否是「最好」的方式,但你可以防止不得不遍歷兩次進行「smoothe」結果:

def collect_key_paths(hash, path = []) 
    items = [] 
    hash.each do |k, v| 
    if v.is_a?(Hash) 
     items.push(*collect_key_paths(v, path + [k])) 
    else 
     items << (path + [k]) 
    end 
    end 
    items 
end 

p collect_key_paths(x) 
0
class Hash 
    def collect_key_paths(path=[]) 
    self.each.with_object([]) do |(k, v), a| 
     if v.kind_of?(Hash) 
     a.push(*v.collect_key_paths(path + [k])) 
     else 
     a << path + [k] 
     end 
    end 
    end 
end 

所以,下面的例子:

x = Hash.new 
x["a"] = Hash.new 
x["a"]["b"] = Hash.new 
x["a"]["b"]["c"] = "one" 
x["a"]["b"]["d"] = "two" 
x["a"]["e"] = "three" 
x["f"] = Hash.new 
x["f"]["g"] = "four" 

puts x.collect_key_paths.inspect 
0

輕微變化:

def collect_key_paths(hash) 
    paths = [] 
    hash.each do |k, v| 
    paths.concat( 
     Hash === v ? 
     collect_key_paths(v).map{ |path| [k, *path]} : 
     [k] 
    ) 
    end 
    paths 
end 
相關問題