In one of my applications, I have a lot of queries that return just an id and a content column for each of the rows in the result. e.g.
Hi --
In one of my applications, I have a lot of queries that return just an id and a content column for each of the rows in the result. e.g.
+----+---------+ > id | content | +----+---------+ > 35 + apple | > 79 + pear | +----+---------+
I'd like to be able to access the object returned by result = Food.find(:all) like result[79] = "pear"
I'm trying to minimize the time needed to convert the Food object into this hash. Does anyone have an idea which method might be the fastest?
You may already have one that's faster than either of these, but for what it's worth, it looks like this:
a = Food.find(:all, :select => "id, content") result = Hash[*a.map {|e| e.attributes.values}.flatten]
is much slower than:
a = Food.find(:all, :select => "id, content") result = {} a.map {|e| result[e.id] = e.content }
Much slower, as in:
user system total real Hash 5.820000 0.030000 5.850000 ( 5.849504) map 0.760000 0.000000 0.760000 ( 0.763521)
I think the first is cooler, but coolth sometimes comes at a price ![]()
David
If you really want to be fast you might avoid the object instantiation and go with direct SQL. But if you don't have to be super fast I would keep it readable and just do something like this:
food_lookup_table = Food.find(:all).inject({}) {|m,f| m[f.id] = f.content; m}
Of course over time I have crafted a nice Enumerable#to_h method to handle many of these common cases so the above translated to:
food_lookup_table = Food.find(:all).to_h :id, :content
If you are interested in my method I have pasted it below. It does a lot more than just the above because I have continued to enhance it over time.
module Enumerable # Abstracts the process of converting a list to a hash. In your block # just return a array where the first value is the key and the second # value is the value. If the key and value are simple method calls # you can just pass in the symbols as arguments. Finally if you just # return a single value (not an array) then it will assume that is # the value and use the enumerable item as the key. If the value is # a simple method and you want to assume the key you can just pass # the value method in.
I don't have your datasest... how does the following compare?
a = Food.find(:all, :select=>'id, content') a.inject({}){|collection, item| collection.merge item;id=>item.content}
Perhaps as a result of all the PED talk in baseball, I've become quite
a fan of inject-ing things. ![]()
Hi --
Oops. Lazy ring finger. ![]()