require 'date'
dates = [
'2011-01-20',
'2011-01-23',
'2011-02-01',
'2011-02-15',
'2011-03-21'
].map{|sd| Date.parse(sd)}
Hash[
dates.group_by(&:year).map{|y, items|
[y, items.group_by{|d| d.strftime('%B')}]
}
]
#=> {2011=>{"January"=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>], "February"=>[#<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>], "March"=>[#<Date: 2011-03-21 (4911283/2,0,2299161)>]}}
Я заметил, что вы поменяли названия месяцев на числа, поэтому вы можете заменить d.strftime('%B')
выше на d.month
или что-то еще.
Вот пошаговое объяснение:
По сути, вам нужна двухуровневая группировка: первый по годам, второй по месяцам.В Ruby есть очень полезный метод group_by
, который группирует элементы по заданному выражению (блоку).Итак: первая часть группирует исходный массив по year
:
hash_by_year = dates.group_by(&:year)
# => {2011=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>, #<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>, #<Date: 2011-03-21 (4911283/2,0,2299161)>]}
Это дает нам первый уровень: ключи - это годы, массивы значений дат с данным годом.Но нам все еще нужно сгруппировать второй уровень: поэтому мы сопоставляем хэш по годам - чтобы сгруппировать его значения по month
.Давайте для начала забудем strftime
и скажем, что мы группируемся по d.month
:
hash_by_year.map{|year, dates_in_year|
[year, dates_in_year.group_by(&:month)]
}
# => [[2011, {1=>[#<Date: 2011-01-20 (4911163/2,0,2299161)>, #<Date: 2011-01-23 (4911169/2,0,2299161)>], 2=>[#<Date: 2011-02-01 (4911187/2,0,2299161)>, #<Date: 2011-02-15 (4911215/2,0,2299161)>], 3=>[#<Date: 2011-03-21 (4911283/2,0,2299161)>]}]]
Таким образом, мы получили группировку второго уровня.Вместо массива всех дат в году, теперь у нас есть хеш, ключи которого - месяцы, и значения массивов дат для данного месяца.
Единственная проблема, которую мы имеем, состоит в том, что map
возвращает массив, а нехешВот почему мы «окружаем» целое выражение Hash[]
, что делает хэш из массива пар, в нашем случае пар [year, hash_of_dates_by_month]
.
Извините, если объяснение звучит запутанно, мне сложнее объяснить функциональноевыражения, чем императив, из-за вложенности.(