map や select などのメソッドの遅延評価版を提供する。
成果物
情報源
Enumerator::Lazy
map や select などのメソッドの遅延評価版を提供するためのクラス。
動作は通常の Enumerator と同じですが、以下のメソッドが遅延評価を行う (つまり、配列ではなく Enumerator を返す) ように再定義されています。
map
/collect
flat_map
/collect_concat
filter_map
select/find_all
reject
grep
,grep_v
take
,take_while
drop
,drop_while
slice_before
,slice_after
,slice_when
chunk
,chunk_while
uniq
zip
(※互換性のため、ブロックを渡さないケースのみlazy)
Lazyオブジェクトは、Enumerable#lazyメソッドによって生成されます。
Lazyから値を取り出すには、Enumerator::Lazy#force または Enumerable#first を呼びます。
例:
# 二乗して偶数になるような整数を、小さい方から5個表示する p 1.step.lazy.select{|n| (n**2).even?}.first(5) # LTSV (http://ltsv.org/) 形式のログファイルから検索を行う # Enumerator::Lazy#map は配列ではなく Enumerator を返すため、 # 巨大な配列を確保しようとしてメモリを使い切ったりはしない open("log.txt"){|f| f.each_line.lazy.map{|line| Hash[line.split(/\t/).map{|s| s.split(/:/, 2)}] }.select{|hash| hash["req"] =~ /GET/ && hash["status"] == "200" }.each{|hash| p hash } }
メンバ抜粋
特異メソッド
new
インスタンスメソッド
chunk chunk_while collect collect_concat drop drop_while eager enum_for filter filter_map find_all flat_map force grep grep_v lazy map reject select slice_after slice_before slice_when take take_while to_enum uniq zip
new
Enumerator::Lazy#force メソッドなどによって列挙が実行されたとき、objのeachメソッドが実行され、値が一つずつブロックに渡されます。ブロックは、yielder を使って最終的に yield される値を指定できます。
new(obj, size=nil) {|yielder, *values| ... } -> Enumerator::Lazy
module Enumerable def filter_map(&block) map(&block).compact end end class Enumerator::Lazy def filter_map Lazy.new(self) do |yielder, *values| result = yield *values yielder << result if result end end end 1.step.lazy.filter_map{|i| i*i if i.even?}.first(5) # => [4, 16, 36, 64, 100]
所感
直接生成するよりもlazy
メソッドによって返されるものを利用するというシーンが多そうか。むしろ基本的にlazy
であり配列化したいときにto_a
するのか?
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
- Ruby 3.0.2
$ uname -a Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux