如何从散列哈希中有效地提取具有某个键名的所有值?

时间:2013-03-16 13:50:50

标签: ruby arrays hash

我有这些数据:

members = {"total"=>3, "data"=>[
  {"email"=>"foo@example.org", "timestamp"=>"2013-03-16 01:11:01"},
  {"email"=>"bar@example.org", "timestamp"=>"2013-03-16 02:07:30"},
  {"email"=>"exx@example.org", "timestamp"=>"2013-03-16 03:06:24"}
]}

想要生成如下数组:

["foo@example.org", "bar@example.org", "exx@example.org"]

目前我正在使用:

members['data'].collect { |h| h['email'] }
  1. 在性能方面是否有更有效的方法来实现它?
  2. 是否有更短的方法来实现它?
  3. 我有Rails可用。

3 个答案:

答案 0 :(得分:4)

除了其他答案之外,如果您能够Hash使用symbols构建keys performance,我可以添加require 'benchmark' members_without_sym = {"total"=>3, "data"=>[ {"email"=>"foo@example.org", "timestamp"=>"2013-03-16 01:11:01"}, {"email"=>"bar@example.org", "timestamp"=>"2013-03-16 02:07:30"}, {"email"=>"exx@example.org", "timestamp"=>"2013-03-16 03:06:24"} ]} members_with_sym = {:total=>3, :data=>[ {:email=> "foo@example.org", :timestamp => "2013-03-16 01:11:01"}, {:email=> "bar@example.org", :timestamp => "2013-03-16 02:07:30"}, {:email=> "exx@example.org", :timestamp=> "2013-03-16 03:06:24"} ]} Benchmark.bm(1) do |algo| algo.report("Without symbol"){ 2_000_000.times do members_without_sym['data'].collect { |h| h['email'] } end } algo.report("With symbol"){ 2_000_000.times do members_with_sym[:data].collect { |h| h[:email] } end } end 时获得 user system total real Without symbol 2.260000 0.000000 2.260000 ( 2.254277) With symbol 0.880000 0.000000 0.880000 ( 0.878603) 增益收集值,例如:

{{1}}

结果:

{{1}}

答案 1 :(得分:3)

除了将h['email']部分优化为原生扩展之外,我无法看到如何使上述示例更有效。这样做的效率增益对于数据集的示例大小来说是微不足道的,并且比我首先想到的优化获取/解析这些数据的I / O要小得多。

根据您的数据源,将散列键作为标签而不是字符串,是一种常见的Ruby习惯用法,在内存使用方面也更有效。这可能是效率的更大提升,并且可能是值得的,只要您不必花费大量精力来转换数据(例如,您可以以某种方式改变数据源中给定数据结构的性质,无需转换哈希只是为了查询一次!)

答案 2 :(得分:2)

members = {"total"=>3, "data"=>[
  {"email"=>"foo@example.org", "timestamp"=>"2013-03-16 01:11:01"},
  {"email"=>"bar@example.org", "timestamp"=>"2013-03-16 02:07:30"},
  {"email"=>"exx@example.org", "timestamp"=>"2013-03-16 03:06:24"}
]}

temp = members["data"].map{|x|x["email"]}

给你[“foo@example.org”,“bar @ example.org”,“exx@example.org”]

Difference between map and collect in Ruby?

-

也许Structs可以提高性能

Record = Struct.new(:email, :timestamp)
members = {"total"=>3, "data"=>[
  Record.new("foo@example.org","2013-03-16 01:11:01"),
  Record.new("bar@example.org","2013-03-16 02:07:30"),
  Record.new("exx@example.org","2013-03-16 03:06:24")
]}

temp = members["data"].map(&:email)

http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html