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.month
或其他任何替代d.strftime('%B')
。
這裏有一個一步一步的解釋:
基本上只是想要兩個級別的分組:由今年第一級,第二通過一個月。 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]
。
對不起,如果解釋聽起來令人困惑,由於嵌套,我發現很難解釋函數表達式而不是命令式。 :(
,除非你打算來表達他們的八進制。無論哪種方式,如果哈希是檢查的形式,則不應把'0'在哈希個月前,'0'應該不會出現。 – sawa 2011-04-12 19:03:18
@sawa謝謝,我只是做這件事而忘了這件事,它不是實際的粘貼數據 – slhck 2011-04-12 19:44:36