[英]How to group_by this array of hashs (Enumerable) [Ruby, Rails]
[英]How to group Ruby enumerable/array by more than one field?
我有一個數據結構事件:
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)
我想根據操作和日期對數據進行分組,以獲得最終結果:
{
"action1" => {'1/8/2014' => 3, '8/8/2014' => 1 },
"action2" => {'1/8/2014' => 1, '2/8/2014' => 2 }
}
最終結果顯示,動作1在“ 1/8/2014”重復了3次,在“ 8/8/2014”重復了1次。 動作2在“ 1/8/2014”一次,在“ 2/8/2014”兩次。
我嘗試先使用#group_by{|x| x.action}
通過操作將結果#group_by{|x| x.action}
#group_by{|x| x.action}
然后試圖用注射,但我的解決方案是什么,但簡單。
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
@sawa提供了一個不錯的解決方案,但這里還有兩個。 我更喜歡第一個,第二個則不太喜歡,盡管我認為可以簡化一些。
#1
這利用了采用一個塊的Hash#update (又名merge
)的形式。 該塊僅對鍵值對起作用,鍵值對由正在構建的哈希和正在合並的哈希包含鍵。 回想一下,當在塊中未使用塊變量時,可以用下划線(或下划線后跟描述符,例如_key
) _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}}
如果有興趣,我將很樂意為您介紹這兩種方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.