Reputation: 1962
let's say I have an array like so:
groups = [
["G1", ["A0640", "A0660", "A0647", "A0643", "A0604", "A0644"]],
["G2", ["A1609","A1611","A1608","A1610"]],
["G3", ["A0613", "A0619", "A0637", "A0636"]],
["G4", ["A0646", "A0610", "A0645"]],
["G5", ["A0616", "A0611", "A0638", "A0606", "A0602", "A0639", "A0626", "A0605"]]
]
What i do to find the key or x[0] of the array element is by using :
groups .detect{|x,y| y.detect{|o| o == "A0619"} }[0]
is there's any better way of doing it?
Upvotes: 0
Views: 96
Reputation: 118271
How is this ?
groups = [
["G1", ["A0640", "A0660", "A0647", "A0643", "A0604", "A0644"]],
["G2", ["A1609","A1611","A1608","A1610"]],
["G3", ["A0613", "A0619", "A0637", "A0636"]],
["G4", ["A0646", "A0610", "A0645"]],
["G5", ["A0616", "A0611", "A0638", "A0606", "A0602", "A0639", "A0626", "A0605"]]
]
Hash[groups].detect{|_,v| v.include? "A0619" }.first
# => "G3"
update
groups = [
["G1", ["A0640", "A0660", "A0647", "A0643", "A0604", "A0644"]],
["G2", ["A1609","A1611","A1608","A1610"]],
["G3", ["A0613", "A0619", "A0637", "A0636"]],
["G4", ["A0646", "A0610", "A0645"]],
["G5", ["A0616", "A0611", "A0638", "A0606", "A0602", "A0639", "A0626", "A0605"]]
]
groups[groups.index{|_,a| a.include? "A0619"}][0]
# => "G3"
BenchMark
require "benchmark"
groups = [
["G1", ["A0640", "A0660", "A0647", "A0643", "A0604", "A0644"]],
["G2", ["A1609","A1611","A1608","A1610"]],
["G3", ["A0613", "A0619", "A0637", "A0636"]],
["G4", ["A0646", "A0610", "A0645"]],
["G5", ["A0616", "A0611", "A0638", "A0606", "A0602", "A0639", "A0626", "A0605"]]
]
Benchmark.bm(8) do |x|
x.report("falsetru:") do
1_000_000.times { groups.detect{|x,y| y.detect{|o| o == "A0619"} }[0] }
end
x.report("Arup1") do
1_000_000.times { groups[groups.index{|_,a| a.include? "A0619"}][0] }
end
x.report("Arup2") do
1_000_000.times do
Hash[groups].detect{|_,v| v.include? "A0619" }.first
end
end
end
output
user system total real
falsetru: 8.860000 0.000000 8.860000 ( 8.885295)
Arup1 2.780000 0.000000 2.780000 ( 2.800791)
Arup2 7.800000 0.000000 7.800000 ( 7.825369)
Upvotes: 0
Reputation: 5558
I guess we can assume that by "better" you mean "faster"? If the speed (not the syntax) is the issue, then you can easily measure how much time does it take using different proposed solutions:
Benchmark.bm(8) do |x|
x.report("detect:") do
1_000_000.times { groups.detect{|x,y| y.detect{|o| o == "A0619"} }[0] }
end
x.report("include:") do
1_000_000.times { groups.detect{|x,y| y.include? "A0619" }[0] }
end
x.report("rassoc:") do
1_000_000.times { groups.map(&:flatten).rassoc("A0613").first }
end
x.report("hashwc:") do
1_000_000.times do
hash = Hash[groups.flat_map { |key, values| values.map { |value| [value, key] } }]
hash['A0619']
end
end
x.report("hash-x:") do
1_000_000.times do
Hash[groups].detect{|_,v| v.include? "A0619" }.first
end
end
end
user system total real
detect: 6.480000 0.020000 6.500000 ( 6.523376)
include: 2.650000 0.000000 2.650000 ( 2.658573)
rassoc: 9.920000 0.150000 10.070000 ( 10.099147)
hashwc: 21.440000 0.040000 21.480000 ( 21.543540)
hash-x: 5.690000 0.010000 5.700000 ( 5.725335)
Directly accessing hash by the key 1 million times is way faster than any of this methods, so if you can store this array as a hash, you should go for it (but only if it wouldn't require to convert the array every time).
Upvotes: 1
Reputation: 369094
You can use Enumerable#include?
instead of Enumerable#detect
:
groups.detect{|x,y| y.include? "A0619" }[0]
# => "G3"
If you need to do this operation multiple times, it's better to create a hash:
groups = [
["G1", ["A0640", "A0660", "A0647", "A0643", "A0604", "A0644"]],
["G2", ["A1609","A1611","A1608","A1610"]],
["G3", ["A0613", "A0619", "A0637", "A0636"]],
["G4", ["A0646", "A0610", "A0645"]],
["G5", ["A0616", "A0611", "A0638", "A0606", "A0602", "A0639", "A0626", "A0605"]]
]
hash = Hash[groups.flat_map { |key, values| values.map { |value| [value, key] } }]
hash['A0619']
# => "G3"
Upvotes: 0