xml - Better way to retrieve values from matching keys in a ruby hash -
i'm trying create faster parser soap api turn xml hash, , match keys memory loaded schema based on yml structure. used nori parse xml hash:
hash1 = { :key1 => { :@attr1=> "value1", :key2 => { :@attribute2 => "value2" }}}
(old ruby syntax keep attributes keys clear)
meanwhile have constant loaded in memory , stores relevant keys needed actions:
hash2 = {:key1 => { :key2 => { :@attribute2 => nil }}}
(old ruby syntax keep attributes keys clear)
i need match first hash second 1 in efficient way. per understanding there ways it:
iterate on 2 hash keys @ same time using second 1 origin:
def iterate(hash2, hash1) hash2.each |k, v| if v.is_a? hash iterate(hash2[k], hash1[k]) else hash2[k] = hash1[k] end end end
(multiline syntax, ¿clear?)
some questions come mind:
- is there more efficient way without having iterate on keys?
- is more efficient accessing keys directly?
- is there better way parse xml hash using hash2 inside visitor pattern?
the solution without iteration recursive select:
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 |k, _| h2.keys.include? k end.map |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"}}}
in general, select
supposed better each
because of sophisticated selection algorithm. in reality, difference 20%.
require 'benchmark' hash = (1..1_000_000).map { |i| ["key#{i}", i] }.to_h n = 5 benchmark.bm |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)