我有一个数据结构事件:
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)
我想根据操作和 date 对数据进行分组,以获得最终结果:
{
"action1" => {'1/8/2014' => 3, '8/8/2014' => 1 },
"action2" => {'1/8/2014' => 1, '2/8/2014' => 2 }
}
最终结果显示,action1在'1/8/2014'重复了3次,在'8/8/2014'重复了一次。并且行动2在'1/8/2014'一次,两次在'2/8/2014'。
我尝试使用#group_by{|x| x.action}
首先按行动对结果进行分组,然后尝试使用注入,但我的解决方案不是简单的。
答案 0 :(得分:2)
Hash.new{|h, k| h[k] = Hash.new{|h, k| h[k] = 0}}
.tap{|h| data.each{|e| h[e.action][e.date] += 1}}
结果h
是:
{
"action1" => {"1/8/2014" => 3, "8/8/2014" => 1},
"action2" => {"1/8/2014" => 1, "2/8/2014" => 2}
}
,或者
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
答案 1 :(得分:1)
<强>#1 强>
这个使用了Hash#update(又名merge
)的形式。该块仅对键值对起作用,其中键由正在构建的哈希和正在合并的哈希包含。回想一下,当块中没有使用块变量时,块变量可以用下划线(或下划线后跟描述符,例如_key
)替换。 (使用下划线只会引起人们的注意。)
data.each_with_object({}) do |d,h|
h.update({ d.action=>{ d.date=>1 } }) do |_,ohash,_|
ohash[d.date] = (ohash[d.date] || 0) + 1
ohash
end
end
#=> {"action1"=>{"1/8/2014"=>3, "8/8/2014"=>1},
# "action2"=>{"1/8/2014"=>1, "2/8/2014"=>2}}
<强>#2 强>
第二种方法在两个级别分别使用Enumerable#group_by,按行动分组,然后按日期分组。
data.map { |d| [d.action, d.date] }
.group_by(&:first)
.tap { |h| h.keys.each { |k|
h[k]=h[k].group_by { |_,d| d }
.tap { |g| g.keys.each {|kk| g[kk]=g[kk].size} } } }
#=> {"action1"=>{"1/8/2014"=>3, "8/8/2014"=>1},
# "action2"=>{"1/8/2014"=>1, "2/8/2014"=>2}}
如果有兴趣的话,我很乐意为这两种方法提供解释。