Yakob Ubaidi
Yakob Ubaidi

Reputation: 1962

ruby storing and finding data in 2D array with keys alike

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

Answers (3)

Arup Rakshit
Arup Rakshit

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

mdrozdziel
mdrozdziel

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

falsetru
falsetru

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

Related Questions