2015-04-23 48 views
0

我想創建一個更快的解析器的SOAP API,將xml變成一個散列,並匹配的內存加載架構的密鑰基於YML結構。我用紫菜將XML解析成一個哈希:更好的方法來檢索紅寶石哈希中的匹配鍵的值

hash1 = { :key1 => { :@attr1=> "value1", :key2 => { :@attribute2 => "value2" }}} 

(舊的Ruby語法,以保持屬性從按鍵清晰)

同時我有一個加載到內存中一個常數並存儲相關按鍵需要爲我的行爲:

hash2 = {:key1 => { :key2 => { :@attribute2 => nil }}} 

(舊的Ruby語法,以保持屬性從按鍵清晰)

我需要以最有效的方式將第一個散列與第二個散列匹配。按我的理解,有很多方法可以做到這一點:

遍歷同時兩個散列密鑰,但使用第二個爲原點:(?多語法,¿清晰)

def iterate(hash2, hash1) 
    hash2.each do |k, v| 
    if v.is_a? Hash 
     iterate(hash2[k], hash1[k]) 
    else 
     hash2[k] = hash1[k] 
    end 
    end 
end 

一些問題,我想起:

  • 有沒有更有效的方法來做到這一點,而不必遍歷 我所有的鑰匙?
  • 這比直接訪問密鑰效率更高嗎?
  • 有沒有更好的方法來解析XML到一個哈希使用哈希2 內訪客模式?
+0

我不認爲你能避免重複,當你嵌套需要遞歸哈希...我看來,像只有第三個問題(重新設計)可以探索更有效的路徑...也許是有避免需要匹配哈希的方法...?或者,您可以使用StringScanner並編寫您自己的解析器... – Myst

回答

1

迭代而不利用該解決方案可能是遞歸的選擇:

hash1 = { :key1 => { :@attr1=> "value1", 
        :key2 => { :@attribute2 => "value2" }, 
        :key3 => { :@attribute4 => "value4" } }, 
      :key2 => { :@attribute3 => "value3" } 
} 
hash2 = { :key1 => { :key2 => { :@attribute2 => nil }}, 
      :key2 => { :@attribute3 => nil } 
} 

def deep_select h1, h2 
    h1.select do |k, _| 
    h2.keys.include? k 
    end.map do |k, v| 
    v.is_a?(Hash) ? [k, deep_select(v, h2[k])] : [k, v] 
    end.to_h 
end 

puts deep_select hash1, hash2 
#⇒ {:key1=>{:key2=>{:@attribute2=>"value2"}}, :key2=>{:@attribute3=>"value3"}}} 

一般來說,select應該是優於each,因爲複雜的選擇算法。實際上,差距只有20%左右。

require 'benchmark' 

hash = (1..1_000_000).map { |i| ["key#{i}", i] }.to_h 
n = 5 

Benchmark.bm do |x| 
    garbage = 0 
    x.report { hash.each { |_, v| garbage += v } } 
    x.report { hash.select { |_, v| (v % 1000).zero? } } 
end 

#  user  system  total  real 
# 0.400000 0.000000 0.400000 ( 0.391305) 
# 0.320000 0.000000 0.320000 ( 0.321312) 
+0

是不是選擇迭代來查找al鍵? – tebayoso

+0

@JorgedelosSantos一般來說,'select'可能會使用智能查找。用基準更新了答案。 – mudasobwa

+0

談論一百萬個請求時,20%是很多。聽起來像一個答案。 – tebayoso