Gtchweb
Gtchweb

Reputation: 69

Get the average of numbers in an array which is the values of an hash

in a Ruby program I have an hash which has normal strings as keys and the values are array of numbers:

hash_1 = {"Luke"=> [2,3,4], "Mark"=>[3,5], "Jack"=>[2]}

And what I'm looking for is to have as result the same hash with the values that become the average of the numbers inside the arrays:

{"Luke"=> 3, "Mark"=>4, "Jack"=>2}

One way to make it to work can be to create a new empty hash_2, loop over hash_1 and within the block assign the keys to hash_2 and the average of the numbers as values.

hash_2 = {}

hash_1.each do |key, value|
  hash_2[key] = value.sum / value.count
end

hash_2 = {"Luke"=> 3, "Mark"=>4, "Jack"=>2}

Is there a better way I could do this, for instance without having to create a new hash?

Upvotes: 0

Views: 333

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110645

def avg(arr)
  return nil if arr.empty?
  arr.sum.fdiv(arr.size)
end

h = { "Matthew"=>[2], "Mark"=>[3,6], "Luke"=>[2,3,4], "Jack"=>[] }

h.transform_values { |v| avg(v) }
  #=> {"Matthew"=>2.0, "Mark"=>4.5, "Luke"=>3.0, "Jack"=>nil}

Upvotes: 2

Giuseppe Schembri
Giuseppe Schembri

Reputation: 857

This solution is different than the one that use transform_values! because return a new Hash object.

hash_1.map { |k,v| [k, v.sum / v.size] }.to_h

Upvotes: 0

G4143
G4143

Reputation: 2829

@Виктор OK. How about this:

hash_1 = {"Luke"=> [2,3,4], "Mark"=>[3,5], "Jack"=>[2], "Bobby"=>[]}

hash_2 = hash_1.reduce(Hash.new(0)) do |acc, (k, v)|
  v.size > 0 ? acc[k] = v.sum / v.size : acc[k] = 0 
  acc
end

p hash_2

Upvotes: 0

Rajagopalan
Rajagopalan

Reputation: 6064

hash_1 = {"Luke"=> [2,3,4], "Mark"=>[3,5], "Jack"=>[2]}

You don't need another hash for the given below code.

p hash_1.transform_values!{|x| x.sum/x.count}

Result

{"Luke"=>3, "Mark"=>4, "Jack"=>2}

Upvotes: 5

Related Questions