Looking up an array of keys on an array of hashes

2019-09-14 21:27发布

问题:

This post is very similar to my previous one, but the data structures are different here: Joining an array of keys to a hash with key value pairs like excel vlookup

My data from my Mysql2::Result comes back like this array of hashes:

data = [{"isbn" => "1234", "title"=>"apple"},{"isbn" => "5678", "title"=>"banana"},{"isbn" => "2121", "title"=>"car"}]

And my original list of isbns that I would like to compare is this array:

isbns = ["1234","2121", "5454", "5678"]

I'm seeking a function which uses the isbns array and returns a result like this:

result = [{"isbn"=>"1234","title"=>"apple"}, {"isbn"=> "2121", "title"=>"car"}, nil, {"isbn"=>"5678","title"=>"banana"}]

The "driving" array is the isbns... imagine doing a vlookup from isbns to data ... any items that are not in data, but in isbns should return nil. The original order of isbns should be returned, and the return data should be an array of hashes.

回答1:

isbns.map { |isbn| data.find { |h| h["isbn"] == isbn} }
#=> [{"isbn"=>"1234", "title"=>"apple"}, {"isbn"=>"2121", "title"=>"car"}, nil, {"isbn"=>"5678", "title"=>"banana"}]


回答2:

@Michael Kohl's answer is succinct and correct. However if these data sets are big, it's inefficient O(n*m/2). An alternative is to transform the data vector into a hash in O(m) then do the map in O(n) for a runtime of O(n+m).

data_lookup = data.inject({}) {|m,v| m[v["isbn"]] = v; m} # O(data.size)
result = isbns.map { |isbn| data_lookup[isbn] }           # O(isbns.size)

If your data and isbn collections were of size 1000 each, this would be faster by a factor of 250.