0

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?

3 Answers 3

1

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).

Sign up to request clarification or add additional context in comments.

1 Comment

I have added one more solution and added your benchmark into it.. :)
0

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"

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.