Стандартный метод 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"], [], []]
И в итоге вы получите 24 записи в a
, каждая запись будет массивом, а непустые будут содержать события. Вы захотите использовать блочную форму 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 }
Но порядок аргументов для блока другой, и блок должен возвращать массив.