Slide 1

Slide 1 text

Omotesando.rb #63 Omotesando.rb #63 月単位でイテレーションする 月単位でイテレーションする

Slide 2

Slide 2 text

自己紹介 自己紹介 名前:osyo Twitter : github : ブログ : 書いたので気になる人は見 てね! @pink_bangbi osyo-manga Secret Garden(Instrumental) 趣味で気になった bugs.ruby のチケットをブログにまとめてる 令和時代の Ruby 基礎文法最速マスター

Slide 3

Slide 3 text

月単位でイテレーションする 月単位でイテレーションする

Slide 4

Slide 4 text

背景 背景 特定の Date ~ Date 間で日、月、年の日付を取得したかった 日、年の日付はシュッと取得できた 月はちょっと難しかった 今回はどうやって月単位でイテレーションする事ができたのかの思 考を追ってみる話

Slide 5

Slide 5 text

前提条件 前提条件 日付は1 日で固定 2020/04/01 みたに1 日で固定する 2020/04/14 みたいな日付は考慮しない 年をまたぐ可能性もあるよ 2020/04/01 ~ 2022/04/01 間 次の月は Date#next_month で取得できる require "date" puts Date.parse("2020/01/01").next_month # => 2020-02-01

Slide 6

Slide 6 text

Range#step でできないか考えてみる Range#step でできないか考えてみる Date は Range として扱うことができる で特定の日単位でイテレーションできる ただし、月の日数は一定ではないのでこれで対応するのは難しい Range#step require "date" first = Date.parse("2020/01/01") last = Date.parse("2020/01/04") p (first..last).map(&:to_s) # => ["2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04"] # 10 日ごとにイテレーションする first = Date.parse("2020/01/01") last = Date.parse("2020/02/01") p (first..last).step(10).map(&:to_s) # => ["2020-01-01", "2020-01-11", "2020-01-21", "2020-01-31"]

Slide 7

Slide 7 text

Enumerator.new で自前でイテレーションする Enumerator.new で自前でイテレーションする で任意のイテレーションを作る事ができる これを利用して月ごとにイテレーションする Enumerator.new enum = Enumerator.new { |y| # y << を呼ぶたびにイテレーションのブロックを呼び出す # これは 1 〜3 をブロックに渡すような例 y << 1 y << 2 y << 3 } enum.each { |it| p it } # => 1 # 2 # 3

Slide 8

Slide 8 text

いけるやん!!! いけるやん!!! require "date" first = Date.parse("2020/01/01") last = Date.parse("2020/04/01") # 開始の月から終了の月までをイテレーションする enum = Enumerator.new { |y| date = first while date <= last y << date date = date.next_month end } p enum.map(&:to_s) # => ["2020-01-01", "2020-02-01", "2020-03-01", "2020-04-01"]

Slide 9

Slide 9 text

Enumerator.produce を使う Enumerator.produce を使う Enumerator.new を使うと実現できるがやや冗長 そこで という便利メソッドを使う これは与えられたブロックを呼び出し続ける Enumerator を返す Enumerator.produce # 0, 2, 4, 6, 8... と無限に続ける Enumerator を定義 nums = Enumerator.produce(0) { |it| it + 2 } # take を使って先頭から4 つの要素を取り出す pp nums.take(4) # => [0, 2, 4, 6] # ランダムな要素を返す Enumerator を定義 rand = Enumerator.produce { rand(10) } # 10 個のランダムな要素を取り出す pp rand.take(10) # => [1, 1, 6, 3, 4, 0, 1, 9, 1, 1]

Slide 10

Slide 10 text

これを利用して月単位のイテレーションも定義する require "date" first = Date.parse("2020/01/01") last = Date.parse("2020/04/01") # これで開始日から次の月まで永遠とイテレーションする Enumerator を定義する # これだけだと無限ループになる enum = Enumerator.produce(first) { |it| it.next_month } # 試しに先頭5 月分を取得する puts enum.take(5) # => 2020-01-01 # 2020-02-01 # 2020-03-01 # 2020-04-01 # 2020-05-01

Slide 11

Slide 11 text

で終了条件を指定する で終了条件を指定する Enumerator.produce だと無限ループになる を使うことで特定の条件までの要素を取得 完成!!! 完成!!! Enumerable#take_while Enumerable#take_while Enumerable#take_while require "date" first = Date.parse("2020/01/01") last = Date.parse("2020/04/01") # take_while の条件になるまでの値を取得する result = Enumerator.produce(first, &:next_month).take_while { |date| date <= last } puts result # => 2020-01-01 # 2020-02-01 # 2020-03-01 # 2020-04-01

Slide 12

Slide 12 text

まとめ まとめ Enumerator.produce べんり

Slide 13

Slide 13 text

ご清聴 ご清聴 ありがとうございました ありがとうございました