marie
marie

Reputation: 91

How to find average of an array of hashes in Ruby

I am trying to find the averages of several hashes in an array that look like this:

[{"path"=>"/abcd.com", "time"=>0.503},
 {"path"=>"/abcd.com", "time"=>0.765},
 {"path"=>"/abcd.com", "time"=>0.553}]

The arrays are grouped by the path, and I want to find the average time it takes for this path to load.

Here is what I have so far:

 averages = grouped_data.each do |array|
   array.each do |hash|
     hash["time"].reduce(:+) \ hash.length
   end 
 end

It's not working I think because the times in the hashes are floats. So I tried a work around by adding a total and without using reduce, but the total returned 0:

 averages = grouped_data.each do |array|
   total = 0
   array.each do |hash|
     hash["time"] += total \ hash.length
   end 
   return total
 end

I appreciate any help. Thank you!

Upvotes: 3

Views: 3305

Answers (2)

Sagar Pandya
Sagar Pandya

Reputation: 9508

Made an assumption about your grouped_data structure, please verify.

grouped_data = [
                [
                 {"path"=>"/sale.html", "time"=>0.503},
                 {"path"=>"/sale.html", "time"=>0.765},
                 {"path"=>"/sale.html", "time"=>0.553}
                ],
                [
                 {"path"=>"/sales.html", "time"=>1.0},
                 {"path"=>"/sales.html", "time"=>1.0},
                 {"path"=>"/sales.html", "time"=>4.0}
                ]
               ]

If you want the averages per path:

averages = grouped_data.map do |array|
 array.inject(0) do |sum, hash|
   sum + hash["time"]
   end.fdiv(array.size) 
end

 #=> [0.6070000000000001, 2.0]

Or hashes with the path and average times:

avs = grouped_data.map { |array|
  array.inject({}) { |sum, hash|
    sum.merge(hash) { |k, o, n| k == 'time' ? o + n : o }
  }.map { |k, v| [k, k == 'time' ? v.fdiv(array.size) : v] }.to_h
}

 #=> [{ "path" => "/sale.html",  "time" => 0.6070000000000001 },
 #    { "path" => "/sales.html", "time" => 2.0 }]

Upvotes: 1

Ashik Salman
Ashik Salman

Reputation: 1879

Try this:

array = [{"path"=>"/sale.html", "time"=>0.503}, {"path"=>"/sale.html", "time"=>0.765}, {"path"=>"/sale.html", "time"=>0.553}]
average = array.map { |x| x["time"] }.sum / array.size # 0.6070

You can also use sum directly on array:

average = array.sum { |x| x["time"] } / array.size # 0.6070

Upvotes: 3

Related Questions