Reputation: 741
Convert the following hash to another hash.
{["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5}
Convert the above hash to
{["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1}
As you can see the first and second key, value pairs in the hash have same date,
different account, and same user, in this case i need to count the total number
of user posts as two {["2013-08-15", "user1"]=>2}
in the last key, value pair, the count should be one because the user posted to
only one account ("789") even though there are 5 posts {["2013-08-09", "user1"]=>1}
.
Upvotes: 0
Views: 524
Reputation: 67850
Using Facets' Enumerable#frequency you can write this clean and modular one-liner:
require 'facets'
hash1 = {["2013-08-15", "123", "user1"] => 1, ...}
hash2 = hash1.keys.map { |date, code, user| [date, user] }.frequency
#=> {["2013-08-15", "user1"] => 2, ["2013-08-09", "user1"] => 1}
Note that unpacking the values of the array makes easier to see what's going on. Also, note that you don't need to depend on Facets, just add Enumerable#frequency
to your extensions library, it's a very common abstraction.
Upvotes: 3
Reputation: 114128
This can be done with group_by
and map
:
h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5}
Hash[h.group_by { |(u, _, d), _| [u, d] }.map { |u, d| [u, d.size] }]
#=> {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1}
Upvotes: 1
Reputation: 118261
h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789","user1"]=>5}
Hash[h.group_by{|k,v| k[0]}.map{|_,v| [v.flatten.values_at(0,2),v.size]}]
# => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1}
Or,
h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789","user1"]=>5}
h.each_with_object(Hash.new(0)){|((d,_,u),_),hsh| hsh[[d,u]] +=1 }
# => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1}
Upvotes: 2
Reputation: 31564
Not super elegant but works. Also, using arrays as hash keys is kinda weird.
h = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5}
h.inject(Hash.new(0)){|a,((date,post,user),v)| a[[date,user]] +=1; a } # => {["2013-08-15", "user1"]=>2, ["2013-08-09", "user1"]=>1}
Upvotes: 2
Reputation: 1391
hash1 = {["2013-08-15", "123", "user1"]=>1, ["2013-08-15", "456", "user1"]=>1, ["2013-08-09", "789", "user1"]=>5}
hash2 = Hash.new
hash1.each do |x,y|
hash2[ [x[0],x[2]] ] = hash2[ [x[0],x[2]] ].to_i + 1
end
puts hash2
Note that you need to use the .to_i method for first-time initialization, else we'd be adding with nil, but this makes it 0.
Upvotes: 1