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

144 Views

December 23, 21

スライド概要

https://omotesandorb.connpass.com/event/214338/

シェア

埋め込む »CMSなどでJSが使えない場合

各ページのテキスト
1.

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

2.

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

3.

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

4.

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

5.

前提条件 日付は 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

6.

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"]

7.

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 を呼ぶたびにイテレーションのブロックを呼び出す これは 〜 をブロックに渡すような例 これを利用して月ごとにイテレーションする

8.
[beta]
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"]

いけるやん!!!

9.

Enumerator.produce を使う を使うと実現できるがやや冗長 そこで という便利メソッドを使う これは与えられたブロックを呼び出し続ける Enumerator を返す Enumerator.new 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]

10.

これを利用して月単位のイテレーションも定義する 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 を定義する

11.
[beta]
Enumerable#take_while

で終了条件を指定する

だと無限ループになる
を使うことで特定の条件までの要素を取得

Enumerator.produce
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

完成!!!

12.

まとめ Enumerator.produce べんり

13.

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