要約
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
}
}
目次
- 特異メソッド
- インスタンスメソッド
継承しているメソッド
- Enumeratorから継承しているメソッド
- Enumerableから継承しているメソッド
特異メソッド
new(obj, size=nil) {|yielder, *values| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Lazy Enumerator を作成します。Enumerator::Lazy#force メソッドなどによって列挙が実行されたとき、objのeachメソッドが実行され、値が一つずつブロックに渡されます。ブロックは、yielder を使って最終的に yield される値を指定できます。
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]
- [EXCEPTION] ArgumentError:
- 引数を指定しなかった場合、ブロックを指定しなかった場合に発生します。
[SEE_ALSO] Enumerator.new
インスタンスメソッド
chunk {|elt| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]chunk(initial_state) {|elt, state| ... } -> Enumerator::Lazy
-
Enumerable#chunk と同じですが、配列ではなく Enumerator::Lazy を返します。
1.step.lazy.chunk{ |n| n % 3 == 0 } # => #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x007f8bf18118f0>:each>> 1.step.lazy.chunk{ |n| n % 3 == 0 }.take(5).force # => [[false, [1, 2]], [true, [3]], [false, [4, 5]], [true, [6]], [false, [7, 8]]]
[SEE_ALSO] Enumerable#chunk
chunk_while {|elt_before, elt_after| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#chunk_while と同じですが、Enumerator ではなく Enumerator::Lazy を返します。
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
map {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]collect {|item| ... } -> Enumerator::Lazy
-
Enumerable#map と同じですが、配列ではなくEnumerator::Lazy を返します。
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
1.step.lazy.map{ |n| n % 3 == 0 } # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:map> 1.step.lazy.collect{ |n| n.succ }.take(10).force # => [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[SEE_ALSO] Enumerable#map
flat_map {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]collect_concat {|item| ... } -> Enumerator::Lazy
-
ブロックの実行結果をひとつに繋げたものに対してイテレートするような Enumerator::Lazy のインスタンスを返します。
["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force #=> ["f", "o", "o", "b", "a", "r"]
ブロックの返した値 x は、以下の場合にのみ分解され、連結されます。
- x が配列であるか、to_ary メソッドを持つとき
- x が each および force メソッドを持つ (例:Enumerator::Lazy) とき
それ以外のときは、x は分解されず、そのままの値として使われます。
[{a:1}, {b:2}].lazy.flat_map {|i| i}.force #=> [{:a=>1}, {:b=>2}]
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
[SEE_ALSO] Enumerable#flat_map
drop(n) -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#drop と同じですが、配列ではなくEnumerator::Lazy を返します。
- [PARAM] n:
- 要素数を指定します。
- [EXCEPTION] ArgumentError:
- n に負の数を指定した場合に発生します。
1.step.lazy.drop(3) # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:drop(3)> 1.step.lazy.drop(3).take(10).force # => [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[SEE_ALSO] Enumerable#drop
drop_while {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#drop_while と同じですが、配列ではなくEnumerator::Lazy を返します。
1.step.lazy.drop_while { |i| i < 42 } # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:drop_while> 1.step.lazy.drop_while { |i| i < 42 }.take(10).force # => [42, 43, 44, 45, 46, 47, 48, 49, 50, 51]
[SEE_ALSO] Enumerable#drop_while
eager -> Enumerator
[permalink][rdoc][edit]-
自身を遅延評価しない Enumerator に変換して返します。
lazy_enum = (1..).each.lazy # select が遅延評価されるので終了する p lazy_enum.class # => Enumerator::Lazy p lazy_enum.select { |n| n.even? }.first(5) # => [2, 4, 6, 8, 10] # select が遅延評価されないので終了しない enum = lazy_enum.eager p enum.class # => Enumerator p enum.select { |n| n.even? }.first(5)
to_enum(method = :each, *args) -> Enumerator::Lazy
[permalink][rdoc][edit]enum_for(method = :each, *args) -> Enumerator::Lazy
to_enum(method = :each, *args) {|*args| block} -> Enumerator::Lazy
enum_for(method = :each, *args) {|*args| block} -> Enumerator::Lazy
-
Object#to_enum と同じですが、Enumerator::Lazy を返します。
to_enum は「ブロック付きで呼ぶとループを実行し、ブロックを省略した場合は Enumerator を返す」ようなメソッドを定義するときによく使われます。このときに lazy 性が正しく引き継がれるように、Lazy#to_enum は素のEnumerator ではなく Enumerator::Lazy を返すようになっています。
module Enumerable # 要素をn回ずつ繰り返すメソッド # 例:[1,2,3].repeat(2) #=> [1,1,2,2,3,3] def repeat(n) raise ArgumentError if n < 0 if block_given? each do |*val| n.times { yield *val } end else to_enum(:repeat, n) end end end r = 1..10 p r.map{|n| n**2}.repeat(2).first(5) #=> [1, 1, 4, 4, 9] r = 1..Float::INFINITY p r.lazy.map{|n| n**2}.repeat(2).first(5) #=> [1, 1, 4, 4, 9] # Lazy#to_enum のおかげで、repeat の返り値は # もとが Enumerator のときは Enumerator に、 # もとが Lazy のときは Lazy になる
select {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]find_all {|item| ... } -> Enumerator::Lazy
filter {|item| ... } -> Enumerator::Lazy
-
Enumerable#select と同じですが、配列ではなくEnumerator::Lazy を返します。
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
1.step.lazy.find_all { |i| i.even? } # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:find_all> 1.step.lazy.select { |i| i.even? }.take(10).force # => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[SEE_ALSO] Enumerable#select
filter_map {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#filter_map と同じですが、配列ではなく Enumerator::Lazy を返します。
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
1.step.lazy.filter_map { |n| n * 2 if n.even? } # => #<Enumerator::Lazy: #<Enumerator::Lazy: (1.step)>:filter_map> 1.step.lazy.filter_map { |n| n * 2 if n.even? }.take(10).force # => [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
[SEE_ALSO] Enumerable#filter_map
force(*args) -> [object]
[permalink][rdoc][edit]-
全ての要素を含む配列を返します。Lazy から実際に値を取り出すのに使います。
Enumerable#to_a のエイリアスです。
1.step.lazy.take(10).force # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 1.step.lazy.take(10).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grep(pattern) {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#grep と同じですが、配列ではなくEnumerator::Lazy を返します。
(100..Float::INFINITY).lazy.map(&:to_s).grep(/\A(\d)\1+\z/) # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 100..Infinity>:map>:grep(/\A(\d)\1+\z/)> (100..Float::INFINITY).lazy.map(&:to_s).grep(/\A(\d)\1+\z/).take(10).force # => ["111", "222", "333", "444", "555", "666", "777", "888", "999", "1111"]
[SEE_ALSO] Enumerable#grep, Enumerable#grep_v, Enumerator::Lazy#grep_v
grep_v(pattern) {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#grep_v と同じですが、配列ではなくEnumerator::Lazy を返します。
(100..Float::INFINITY).lazy.map(&:to_s).grep_v(/(\d).*\1/) # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 100..Infinity>:map>:grep_v(/(\d).*\1/)> (100..Float::INFINITY).lazy.map(&:to_s).grep_v(/(\d).*\1/).take(15).force # => ["102", "103", "104", "105", "106", "107", "108", "109", "120", "123", "124", "125", "126", "127", "128"]
[SEE_ALSO] Enumerable#grep_v, Enumerable#grep, Enumerator::Lazy#grep
lazy -> self
[permalink][rdoc][edit]-
self を返します。
lazy = (100..Float::INFINITY).lazy p lazy.lazy # => #<Enumerator::Lazy: 100..Infinity> p lazy == lazy.lazy # => true
reject {|item| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#reject と同じですが、配列ではなくEnumerator::Lazy を返します。
- [EXCEPTION] ArgumentError:
- ブロックを指定しなかった場合に発生します。
1.step.lazy.reject { |i| i.even? } # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:reject> 1.step.lazy.reject { |i| i.even? }.take(10).force # => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
[SEE_ALSO] Enumerable#reject
slice_after(pattern) -> Enumerator::Lazy
[permalink][rdoc][edit]slice_after {|elt| bool } -> Enumerator::Lazy
-
Enumerable#slice_after と同じですが、配列ではなく Enumerator::Lazy を返します。
1.step.lazy.slice_after { |e| e % 3 == 0 } # => #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x007fd73980e6f8>:each>> 1.step.lazy.slice_after { |e| e % 3 == 0 }.take(5).force # => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
[SEE_ALSO] Enumerable#slice_after
slice_before(pattern) -> Enumerator::Lazy
[permalink][rdoc][edit]slice_before {|elt| bool } -> Enumerator::Lazy
slice_before(initial_state) {|elt, state| bool } -> Enumerator::Lazy
-
Enumerable#slice_before と同じですが、配列ではなく Enumerator::Lazy を返します。
1.step.lazy.slice_before { |e| e.even? } # => #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x00007f9f31844ce8>:each>> 1.step.lazy.slice_before { |e| e % 3 == 0 }.take(5).force # => [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14]]
[SEE_ALSO] Enumerable#slice_before
slice_when {|elt_before, elt_after| bool } -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#slice_when と同じですが、配列ではなく Enumerator::Lazy を返します。
1.step.lazy.slice_when { |i, j| (i + j) % 5 == 0 } # => #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x00007fce84118348>:each>> 1.step.lazy.slice_when { |i, j| (i + j) % 5 == 0 }.take(5).force # => [[1, 2], [3, 4, 5, 6, 7], [8, 9, 10, 11, 12], [13, 14, 15, 16, 17], [18, 19, 20, 21, 22]]
[SEE_ALSO] Enumerable#slice_when
take(n) -> Enumerator::Lazy
[permalink][rdoc][edit]-
Enumerable#take と同じですが、配列ではなくEnumerator::Lazy を返します。
n が大きな数 (100000とか) の場合に備えて再定義されています。配列が必要な場合は Enumerable#first を使って下さい。
- [PARAM] n:
- 要素数を指定します。
- [EXCEPTION] ArgumentError:
- n に負の数を指定した場合に発生します。
1.step.lazy.take(5) # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:take(5)> 1.step.lazy.take(5).force # => [1, 2, 3, 4, 5]
[SEE_ALSO] Enumerable#take
take_while -> Enumerator::Lazy
[permalink][rdoc][edit]take_while {|item| ... } -> Enumerator::Lazy
-
Enumerable#take_while と同じですが、配列ではなくEnumerator::Lazy を返します。
1.step.lazy.zip(('a'..'z').cycle).take_while { |e| e.first < 100_000 } # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:zip(#<Enumerator: "a".."z":cycle>)>:take_while> 1.step.lazy.zip(('a'..'z').cycle).take_while { |e| e.first < 100_000 }.force.last(5) # => [[99995, "y"], [99996, "z"], [99997, "a"], [99998, "b"], [99999, "c"]]
[SEE_ALSO] Enumerable#take_while
uniq -> Enumerator::Lazy
[permalink][rdoc][edit]uniq {|item| ... } -> Enumerator::Lazy
-
Enumerable#uniq と同じですが、配列ではなく Enumerator::Lazy を返します。
with_index(offset = 0) {|(*args), idx| ... } -> Enumerator::Lazy
[permalink][rdoc][edit]with_index(offset = 0) -> Enumerator::Lazy
-
生成時のパラメータに従って、要素にインデックスを添えて繰り返します。インデックスは offset から始まります。
ブロックを指定した場合の戻り値は生成時に指定したレシーバ自身です。
("a"..).lazy.with_index(1) { |it, index| puts "#{index}:#{it}" }.take(3).force # => 1:a # 2:b # 3:c
[SEE_ALSO] Enumerator#with_index
zip(*lists) -> Enumerator::Lazy
[permalink][rdoc][edit]zip(*lists) {|v1, v2, ...| ... } -> nil
-
Enumerable#zip と同じですが、配列ではなくEnumerator::Lazy を返します。
ただし一貫性のため、ブロック付きで呼び出した場合は Enumerable#zip と同じ挙動になります。
1.step.lazy.zip(('a'..'z').cycle) # => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: 1:step>>:zip(#<Enumerator: "a".."z":cycle>)> 1.step.lazy.zip(('a'..'z').cycle).take(30).force.last(6) # => [[25, "y"], [26, "z"], [27, "a"], [28, "b"], [29, "c"], [30, "d"]]
[SEE_ALSO] Enumerable#zip