【问题标题】:Better way to retrieve values from matching keys in a ruby hash从 ruby​​ 哈希中的匹配键中检索值的更好方法
【发布时间】:2015-07-01 00:51:26
【问题描述】:

我正在尝试为 SOAP API 创建一个更快的解析器,它将 xml 转换为哈希,并将键与基于 YML 结构的内存加载模式进行匹配。我使用 Nori 将 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

(多行语法,¿clear?)

我想到了一些问题:

  • 有没有更有效的方法来做到这一点,而无需迭代 我所有的钥匙?
  • 这是否比直接访问密钥更有效?
  • 有没有更好的方法来使用 hash2 将 XML 解析成哈希 在访客模式中?

【问题讨论】:

  • 我不认为当你有需要递归的嵌套哈希时你可以避免迭代......在我看来,只有第三个问题(重新设计)可以探索更有效的路径......也许有是一种避免需要匹配哈希的方法......?或者,您可以使用 StringScanner 并编写自己的解析器...

标签: ruby xml algorithm hash


【解决方案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)

【讨论】:

  • 不是选择迭代来查找所有键吗?
  • @JorgedelosSantos 一般来说,select 可能会使用智能查找。用基准更新了答案。
  • 20% 在谈到一百万个请求时已经很多了。听起来像是一个答案。
猜你喜欢
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2012-04-21
  • 2013-02-12
  • 2014-10-05
  • 1970-01-01
相关资源
最近更新 更多