0

I've this hash

{
    19132=>{
        :occurences=>34,
        :name=>"bar"
    },
    19133=>{
        :occurences=>19,
        :name=>"foo"
    }
}

I would like to find the addition of occurrences (34+19) in a new key (why not total) on each key (19132 and 19133).

I've something like:

my_hash = {19132=>{:occurences=>34, :name=>"bar"}, 19133=>{:occurences=>19, :name=>"foo"}}
my_hash.values.inject{|memo, el| memo.merge(el){|k, old_v, new_v| old_v + new_v if k.is_a?(Numeric)}}

I've found some help Here but I'm stuck with the merge. I don't even know if this method can solve my problem.

Community
  • 1
  • 1
brcebn
  • 1,571
  • 1
  • 23
  • 46
  • Can you post your desired output? – shivam Feb 16 '15 at 12:51
  • I wouldn't recommend it, but the total could be computed without reference to the key `:occurrences` (note two r's): `hash.values.map(&:values).flatten.reduce(0) { |tot, v| tot + v.to_i } #=> 53`. – Cary Swoveland Feb 16 '15 at 18:27

4 Answers4

1

First, go through all the inner hashes and calculate the total:

total = h.values.inject(0) { |total, hash| total + hash[:ocurrences] }

And then, add the total to the inner hashes:

h.keys.each{|k| h[k][:total] = total}

dgmora
  • 1,239
  • 11
  • 27
0

I tried achieving it in two steps: find total and merge total.

hash = {19132=>{:occurences=>34, :name=>"bar"}, 19133=>{:occurences=>19, :name=>"foo"}}

total = hash.collect(&:first).sum
# => 38265

hash.each{|h| h[1].merge!({"total" => total})}
# => {19132=>{:occurences=>34, :name=>"bar", "total"=>38265}, 19133=>{:occurences=>19, :name=>"foo", "total"=>38265}}
shivam
  • 16,048
  • 3
  • 56
  • 71
0
sum = h.values.inject(0) {|sum, h| sum + h[:occurences] }
# => 53 
h.map {|k, v| v[:total] = sum; [k,v]}.to_h
# => { 19132=>{:occurences=>34, :name=>"bar", :total=>53},
#      19133=>{:occurences=>19, :name=>"foo", :total=>53} }
Santhosh
  • 28,097
  • 9
  • 82
  • 87
  • You can avoid the creation of a temporary array by replacing [Hash#values](http://ruby-doc.org//core-2.2.0/Hash.html#method-i-values) with the enumerator [Hash#each_value](http://ruby-doc.org//core-2.2.0/Hash.html#method-i-each_value). – Cary Swoveland Feb 16 '15 at 22:12
  • @CarySwoveland, But wouldn't that calculate the sum, for each value in the Hash ? – Santhosh Feb 17 '15 at 08:40
  • My apologies for the late reply. I'm not sure if I understand what you are asking, but I'm not suggesting that you change the block, which only references `:occurrences`. Note that `Enumerator.included_modules.first #=> Enumerable`. – Cary Swoveland Feb 18 '15 at 06:35
0

You could do this:

tot = h.each_value.reduce(0) { |t, g| t + g[:occurrences] }
h.merge(h) { |*_,g| g.merge("total"=>tot) }
  # => {19132=>{:occurrences=>34, :name=>"bar", "total"=>53},
  #     19133=>{:occurrences=>19, :name=>"foo", "total"=>53}}

This does not mutate the original hash:

h #=> {19132=>{:occurrences=>34, :name=>"bar"},
  #    19133=>{:occurrences=>19, :name=>"foo"}} 

If you wish to change h in place:

h.merge!(h) { |*_,g| g.merge!("total"=>tot) }

works, but:

h.each_value { |g| g["total"] = tot }

is better.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100