Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to sum values in an array of hashes [closed]

I need to sum values in an array hashes and I found a way to do it here

but it sure seems like there should be a more elegant way in Ruby.

Here is what works;

sales = [{"sale_price"=>210000, "deed_type"=>"Warranty Deed"}, {"sale_price"=>268300, "deed_type"=>"Warranty Deed Joint"}]

total_sales = sales.inject(0) {|sum, hash| sum + hash["sale_price"]}

The totals line is not very readable. It would be nice if something like this worked;

total_sales = sales.sum("sale_price")

Is this just wishful thinking or am I overlooking a better solution?

like image 417
SteveO7 Avatar asked Feb 01 '13 20:02

SteveO7


2 Answers

I like using the map/reduce metaphor like so:

total_sales = sales.map {|s| s['sale_price']}.reduce(0, :+)

The reduce method is a synonym for the inject method, I find the name inject to be somewhat confusing with the memo component. It has another form I use above to take the initial value and a reference to a method call used for the combination/reduction process.

I think the overall pattern of mapping the values and then reducing them to an aggregate is well known and self-documenting.

EDIT: Use symbol :+ instead of proc reference &:+

like image 91
Winfield Avatar answered Nov 16 '22 10:11

Winfield


You can make it work:

sales = [{"sale_price"=>210000, "deed_type"=>"Warranty Deed"}, {"sale_price"=>268300, "deed_type"=>"Warranty Deed Joint"}]

def sales.sum(by)
  inject(0){|sum, h| sum + h[by]}
end

p sales.sum("sale_price") #=> 478300

Note this sum method (sum_by might be a better name) is not defined on Array, but only on the specific sales array.

like image 35
steenslag Avatar answered Nov 16 '22 10:11

steenslag