提高性能以从 Ruby 中的哈希数组中查找 ID 数组
Improve performance to find an array of ids from array of hashes in Ruby
考虑一个哈希数组
a=[{'id'=>'1','imageUrl'=>'abc'},{'id'=>'2','imageUrl'=>'efg'},{'id'=>'3','imageUrl'=>'hij'}]
考虑一个 characters/numbers/ids
的数组
b=['1','2','5']
我想将 b 的 ID 与 a 匹配。对于所有匹配项,我想用相应的哈希替换 b 的值。
在上面的例子中,值'1'和'2'在a和b之间是公共的,所以我将b中的'1'和'2'替换为a对应的哈希值。
所以结果 b 变成
b=[[{"id"=>"1", "imageUrl"=>"abc"}], [{"id"=>"2", "imageUrl"=>"efg"}], []]
我写了下面的代码:
b.each_with_index{|r,index|
puts index
k=a.select {|z| z["id"]==r }
b[index]=k
}
有更好的解决办法吗?一个更圆滑的。我是 ruby.
的新手
你可以使用Enumerable#map, with Enumerable#select
的破坏性版本
b.map! {|id| a.select {|h| h['id'] == id }}
# => [[{"id"=>"1", "imageUrl"=>"abc"}], [{"id"=>"2", "imageUrl"=>"efg"}], []]
这将提高速度:
#!/usr/bin/env ruby
require 'pp'
require 'benchmark'
a = []
5000.times {|c| a << {"id" => "#{c}", "imageUrl" => "test#{c}"}}
b1 = (1..2500).to_a.shuffle.map(&:to_s)
b2 = b1.dup()
puts "method1"
puts Benchmark.measure { b1.map! {|id| a.select {|h| h['id'] == id }} }
puts "method2"
result = Benchmark.measure do
ah = Hash.new([])
a.each{|x| ah[x["id"]] = x}
b2.map!{|be| ah[be]}
end
puts result
结果:
method1
2.820000 0.010000 2.830000 ( 2.827695)
method2
0.000000 0.000000 0.000000 ( 0.002607)
更新基准 - 它在 b 中使用 250000 元素而不是 2500(方法 1 已注释掉以保护无辜者 - 它太慢了我等得无聊了):
#!/usr/bin/env ruby
require 'pp'
require 'benchmark'
a = []
5000.times {|c| a << {"id" => "#{c}", "imageUrl" => "test#{c}"}}
b1 = (1..250000).to_a.collect{|x| x%2500}.shuffle.map(&:to_s)
b2 = b1.dup()
b3 = b1.dup()
# puts "method1"
# puts Benchmark.measure { b1.map! {|id| a.select {|h| h['id'] == id }} }
puts "method2"
result = Benchmark.measure do
ah = Hash.new([])
a.each{|x| ah[x["id"]] = x}
b2.map!{|be| ah[be]}
end
puts result
puts "method3"
result = Benchmark.measure do
h = a.each_with_object({}) { |g,h| h.update(g['id']=>g) }
b3.map! { |s| h.key?(s) ? [h[s]] : [] }
end
puts result
结果是:
method2
0.050000 0.000000 0.050000 ( 0.045294)
method3
0.100000 0.010000 0.110000 ( 0.109646)
[编辑: 发布后我注意到@Mircea 已经发布了相同的解决方案。我会留下我的提及 values_at
替代方案。]
我假设 a
中 :id
的值是唯一的。
首先构造一个查找散列:
h = a.each_with_object({}) { |g,h| h.update(g['id']=>g) }
#=> {"1"=>{"id"=>"1", "imageUrl"=>"abc"},
# "2"=>{"id"=>"2", "imageUrl"=>"efg"},
# "3"=>{"id"=>"3", "imageUrl"=>"hij"}}
然后简单地遍历b
,构造所需的数组:
b.map { |s| h.key?(s) ? [h[s]] : [] }
#=> [[{"id"=>"1", "imageUrl"=>"abc"}],
# [{"id"=>"2", "imageUrl"=>"efg"}],
# []]
或者,
arr = h.values_at(*b)
#=> [{"id"=>"1", "imageUrl"=>"abc"},
# {"id"=>"2", "imageUrl"=>"efg"},
# nil]
然后:
arr.map { |e| e.nil? ? [] : [e] }
#=> [[{"id"=>"1", "imageUrl"=>"abc"}],
# [{"id"=>"2", "imageUrl"=>"efg"}],
# []]
您可能会考虑使用 arr
进行后续计算,因为您所需解决方案中的所有数组最多包含一个元素。
当 b
相对于 a
较大时,查找哈希的使用特别有效。
考虑一个哈希数组
a=[{'id'=>'1','imageUrl'=>'abc'},{'id'=>'2','imageUrl'=>'efg'},{'id'=>'3','imageUrl'=>'hij'}]
考虑一个 characters/numbers/ids
的数组b=['1','2','5']
我想将 b 的 ID 与 a 匹配。对于所有匹配项,我想用相应的哈希替换 b 的值。
在上面的例子中,值'1'和'2'在a和b之间是公共的,所以我将b中的'1'和'2'替换为a对应的哈希值。
所以结果 b 变成
b=[[{"id"=>"1", "imageUrl"=>"abc"}], [{"id"=>"2", "imageUrl"=>"efg"}], []]
我写了下面的代码:
b.each_with_index{|r,index|
puts index
k=a.select {|z| z["id"]==r }
b[index]=k
}
有更好的解决办法吗?一个更圆滑的。我是 ruby.
的新手你可以使用Enumerable#map, with Enumerable#select
的破坏性版本b.map! {|id| a.select {|h| h['id'] == id }}
# => [[{"id"=>"1", "imageUrl"=>"abc"}], [{"id"=>"2", "imageUrl"=>"efg"}], []]
这将提高速度:
#!/usr/bin/env ruby
require 'pp'
require 'benchmark'
a = []
5000.times {|c| a << {"id" => "#{c}", "imageUrl" => "test#{c}"}}
b1 = (1..2500).to_a.shuffle.map(&:to_s)
b2 = b1.dup()
puts "method1"
puts Benchmark.measure { b1.map! {|id| a.select {|h| h['id'] == id }} }
puts "method2"
result = Benchmark.measure do
ah = Hash.new([])
a.each{|x| ah[x["id"]] = x}
b2.map!{|be| ah[be]}
end
puts result
结果:
method1
2.820000 0.010000 2.830000 ( 2.827695)
method2
0.000000 0.000000 0.000000 ( 0.002607)
更新基准 - 它在 b 中使用 250000 元素而不是 2500(方法 1 已注释掉以保护无辜者 - 它太慢了我等得无聊了):
#!/usr/bin/env ruby
require 'pp'
require 'benchmark'
a = []
5000.times {|c| a << {"id" => "#{c}", "imageUrl" => "test#{c}"}}
b1 = (1..250000).to_a.collect{|x| x%2500}.shuffle.map(&:to_s)
b2 = b1.dup()
b3 = b1.dup()
# puts "method1"
# puts Benchmark.measure { b1.map! {|id| a.select {|h| h['id'] == id }} }
puts "method2"
result = Benchmark.measure do
ah = Hash.new([])
a.each{|x| ah[x["id"]] = x}
b2.map!{|be| ah[be]}
end
puts result
puts "method3"
result = Benchmark.measure do
h = a.each_with_object({}) { |g,h| h.update(g['id']=>g) }
b3.map! { |s| h.key?(s) ? [h[s]] : [] }
end
puts result
结果是:
method2
0.050000 0.000000 0.050000 ( 0.045294)
method3
0.100000 0.010000 0.110000 ( 0.109646)
[编辑: 发布后我注意到@Mircea 已经发布了相同的解决方案。我会留下我的提及 values_at
替代方案。]
我假设 a
中 :id
的值是唯一的。
首先构造一个查找散列:
h = a.each_with_object({}) { |g,h| h.update(g['id']=>g) }
#=> {"1"=>{"id"=>"1", "imageUrl"=>"abc"},
# "2"=>{"id"=>"2", "imageUrl"=>"efg"},
# "3"=>{"id"=>"3", "imageUrl"=>"hij"}}
然后简单地遍历b
,构造所需的数组:
b.map { |s| h.key?(s) ? [h[s]] : [] }
#=> [[{"id"=>"1", "imageUrl"=>"abc"}],
# [{"id"=>"2", "imageUrl"=>"efg"}],
# []]
或者,
arr = h.values_at(*b)
#=> [{"id"=>"1", "imageUrl"=>"abc"},
# {"id"=>"2", "imageUrl"=>"efg"},
# nil]
然后:
arr.map { |e| e.nil? ? [] : [e] }
#=> [[{"id"=>"1", "imageUrl"=>"abc"}],
# [{"id"=>"2", "imageUrl"=>"efg"}],
# []]
您可能会考虑使用 arr
进行后续计算,因为您所需解决方案中的所有数组最多包含一个元素。
当 b
相对于 a
较大时,查找哈希的使用特别有效。