假设我有几周内存储为哈希的事件列表,每个事件都带有DateTime
:date
键。
有什么方法可以把它变成一系列事件,按小时分组。也就是说,第一个条目用于小时#1中的事件,第二个条目用于小时#2中的事件等。
事件样本列表:
e = [ { :date => (DateTime), :name => "event 1" },
{ :date => (DateTime), :name => "event 2" } ]
首先,我计算了日期范围内的所有小时数,并在完成小时后将匹配的数据添加到数组中。但这对我来说似乎非常不像红宝石。
我找到了Enumerable#group_by
方法,但这只创建了包含事件的小时“容器”而没有跳过任何事件。
这个问题有一个干净的功能方法吗?如果没有,是否有一种优雅的红宝石般的方式呢?
另外,如何将对分组呢?如同,两个小时的团体。或者每组任意数小时。
答案 0 :(得分:4)
标准each_with_object
方法是您的朋友,如果h
包含DateTime键和事件作为值,则:
h = {
DateTime.new('2011-06-03 12:34') => 'event one',
DateTime.new('2011-06-11 22:00:00') => 'event two'
}
a = h.each_with_object(Array.new(24) { [] }) { |(k,v), a| a[k.hour - 1].push(v) }
# a is now [[], [], [], [], [], [], [], [], [], [], [], ["event one"], [], [], [], [], [], [], [], [], [], ["event two"], [], []]
你最终会在a
中输入24个条目,每个条目都是一个数组,非空的条目将包含这些事件。您将需要使用Array.new
的块形式,以便将不同的数组作为默认值。
如果你想将小时分成两小时的跨度:
a = h.each_with_object(Array.new(12) { [] }) { |(k,v), a| a[((k.hour - 1) / 2).to_i].push(v) }
# a is now [[], [], [], [], [], ["event one"], [], [], [], [], ["event two"], []]
然后您可以轻松地将a
的索引转换为输出的时间范围。
进一步概括是留给读者的练习。
如果您遇到1.8并且您不在Rails环境中,那么您可以使用inject
获得相同的结果:
h.inject(Array.new(24) { [ ] }) { |a, (k,v)| a[k.hour - 1].push(v); a }
但是块的参数顺序是不同的,并且块必须返回数组。