map や select などのメソッドの遅延評価版を提供する。
成果物
情報源
Enumerator::Lazy
map や select などのメソッドの遅延評価版を提供するためのクラス。
動作は通常の Enumerator と同じですが、以下のメソッドが遅延評価を行う (つまり、配列ではなく Enumerator を返す) ように再定義されています。
map/collectflat_map/collect_concatfilter_mapselect/find_allrejectgrep,grep_vtake,take_whiledrop,drop_whileslice_before,slice_after,slice_whenchunk,chunk_whileuniqzip(※互換性のため、ブロックを渡さないケースのみ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