2015-04-23 20 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