Eki Eqbal Eki Eqbal - 5 months ago 20
Ruby Question

How to group Ruby enumerable/array by more than one field?

I have a data structure Event:

Event = Struct.new(:action, :date, :id)

data= []
data << Event.new('action1', '1/8/2014', 1)
data << Event.new('action1', '1/8/2014', 2)
data << Event.new('action1', '1/8/2014', 3)
data << Event.new('action1', '8/8/2014', 4)
data << Event.new('action2', '1/8/2014', 5)
data << Event.new('action2', '2/8/2014', 6)
data << Event.new('action2', '2/8/2014', 7)


I want to group data based on action and date, to get final result:

{
"action1" => {'1/8/2014' => 3, '8/8/2014' => 1 },
"action2" => {'1/8/2014' => 1, '2/8/2014' => 2 }
}


The final result shows that action1 repeated 3 times at '1/8/2014' and one time at '8/8/2014'. And action2 one time at '1/8/2014' and two times at '2/8/2014'.

I tried to group results first by action using
#group_by{|x| x.action}
then tried to use inject but my solution is anything but simple.

Answer Source
Hash.new{|h, k| h[k] = Hash.new{|h, k| h[k] = 0}}
.tap{|h| data.each{|e| h[e.action][e.date] += 1}}

result h is:

{
  "action1" => {"1/8/2014" => 3, "8/8/2014" => 1},
  "action2" => {"1/8/2014" => 1, "2/8/2014" => 2}
}

or,

data.each_with_object(Hash.new{|h, k| h[k] = Hash.new{|h, k| h[k] = 0}}) do
  |e, h| h[e.action][e.date] += 1
end