Tuesday, February 12, 2008

collect and flatten

I run into this scenario many times and never really thought about changing it until recently. It's very common, I have an array of values and I want to perform an action on each item. My return value would be an array of the results from the action.

Here's a sample lookup that most likely will return an array (unless it's a small city):
def zip_codes_for_city(city)
ZipCode.find(:all, :conditions => ["city = ?",city])
end
So then I want to get the values for a list of cities. I would, without thinking about it, do the following:
def zip_codes_for_cities(cities)
rvalue = []
cities.each do |city|
rvalue << zip_codes_for_city(city)
end
rvalue
end
That is really readable and easy to follow. Without losing too much readability, we can shorten this by doing the following:
def zip_codes_for_cities(cities)
rvalue =[]
cities.each{|city| rvalue << zip_codes_for_city(city)}
rvalue
end
If you are know a little more about Ruby, this will be equally readable and much more succinct:
def zip_codes_for_cities(cities)
cities.collect{|city| zip_codes_for_city(city)}.flatten
end
If there are no performance differences, then the format would depend on the audience. In a high usage application, the introduction of the extra rvalue variable would seemingly increase your memory footprint. I haven't benchmarked that, just an assumption.

0 comments: