代碼
require 'date'
def fill_in_missing_months(dates)
date_fmt = '%b %Y'
fm, lm = dates.keys.
minmax_by { |date| Date.strptime(date, date_fmt) }.
map { |date| Date.strptime(date, date_fmt) }
(0..12*(lm.year-fm.year) + lm.month-fm.month).each_with_object({}) do |_,h|
str = fm.strftime(date_fmt)
h[str] = dates.fetch(str, 0)
fm >>= 1
end
end
例
dates = {"Apr 2016"=>6, "Aug 2016"=>9, "Jan 2017"=>11, "Apr 2017"=>6,
"May 2017"=>9, "Jun 2017"=>1, "Jul 2017"=>9}
fill_in_missing_months(dates)
#=> {"Apr 2016"=>6, "May 2016"=>0, "Jun 2016"=>0, "Jul 2016"=>0, "Aug 2016"=>9,
# "Sep 2016"=>0, "Oct 2016"=>0, "Nov 2016"=>0, "Dec 2016"=>0, "Jan 2017"=>11,
# "Feb 2017"=>0, "Mar 2017"=>0, "Apr 2017"=>6, "May 2017"=>9, "Jun 2017"=>1,
# "Jul 2017"=>9}
說明
經驗Rubiests:一個血淋淋的細節,如下公告已經發布,所以你可以跳過我的答案的其餘部分。
Ruby在解析代碼時將fm >>= 1
擴展爲fm = fm >> 1
。 Date#>>提前日期由其參數給出的月數,這裏是1
。
除了:>>
,看該文檔的方法Integer#times,Hash#fetch,Date::strptime,Date#strftime,Date#year,Date#month,Enumerator#with_object和Enumerable#minimax_by(不包括更常用的方法如Enumerable#map
)。回憶#
Date#year
表示實例方法,而::
[Date::strptime]
表示類方法。
對於示例中給出的dates
,其步驟如下。
date_fmt = '%b %Y'
b = dates.keys
#=> ["Apr 2016", "Aug 2016", "Jan 2017", "Apr 2017", "May 2017",
# "Jun 2017", "Jul 2017"]
c = b.minmax_by { |date| Date.strptime(date, date_fmt) }
#=> ["Apr 2016", "Jul 2017"]
fm, lm = c.map { |date| Date.strptime(date, date_fmt) }
#=> [#<Date: 2016-04-01 ((2457480j,0s,0n),+0s,2299161j)>,
# #<Date: 2017-07-01 ((2457936j,0s,0n),+0s,2299161j)>]
fm #=> #<Date: 2016-04-01 ((2457480j,0s,0n),+0s,2299161j)>
lm #=> #<Date: 2017-07-01 ((2457936j,0s,0n),+0s,2299161j)>]
d = 0..12*(lm.year-fm.year) + lm.month-fm.month
#=> 0..15
e = d.each_with_object({})
#=> #<Enumerator: 0..15:each_with_object({})>
我們可以通過將其轉換爲一個數組,使用Enumerable#entries(或Enumerable#to_a)看到將由e
生成並傳遞到該塊中的值。
e.entries
#=> [[0, {}], [1, {}],..., [15, {}]]
在這些元組的哈希最初是空的,但隨着塊執行計算將被填充。
第一元件由e
,它被傳遞給塊產生和塊變量被設置等於它的值,使用一種稱爲消歧或分解過程刺出與每個塊變量相關聯的部分。
_,h = e.next
#=> [0, {}]
h #=> {}
我使用_
作爲第一塊變量以表示它(指數)沒有在塊計算中使用。繼續,
str = fm.strftime(date_fmt)
#=> "Apr 2016"
h[str] = dates.fetch(str, 0)
#=> 6
h #=> {"Apr 2016"=>6}
在這種情況下dates
有一個關鍵"Apr 2016"
,所以h["Apr 2016"]
設置等於dates["Apr 2016"]
。在其他情況下,dates
將不具有等於str
(例如"May 2016"
)的密鑰,因此該值將被設置爲等於fetch
的默認值0
。
fm >>= 1
#=> #<Date: 2016-05-01 ((2457510j,0s,0n),+0s,2299161j)>
fm
現在是2016年5月。其餘的計算是類似的。
你見過「[在兩個日期之間獲取獨特的月份和年份數組](https://stackoverflow.com/questions/45064402/get-unique-array-of-month-and-years-between-two-日期/ 45064684)「?這個問題將第一個和最後一個月之間的所有月份都當作一個數組......並且如果能得到第一個和最後一個月,那麼這些答案可以很容易地修改以填充散列的缺失月份。 –