要約
each 以外のメソッドにも Enumerable の機能を提供するためのラッパークラスです。また、外部イテレータとしても使えます。
Enumerable モジュールは、 Module#include 先のクラスが持つ each メソッドを元に様々なメソッドを提供します。例えば Array#map は Array#each の繰り返しを元にして定義されます。 Enumerator を介することにより String#each_byte のような異なる名前のイテレータについても each と同様に Enumerable の機能を利用できます。
Enumerator を生成するには Enumerator.newあるいは Object#to_enum, Object#enum_for を利用します。また、一部のイテレータはブロックを渡さずに呼び出すと繰り返しを実行する代わりに enumerator を生成して返します。
注意
外部イテレータとしての機能は Fiber を用いて実装されているため Fiber と同じ制限があります。例えば以下のようなスレッドをまたいだ呼び出しはエラーになります。
a = nil
Thread.new do
a = [1, 2, 3].each
a.next
end.join
p a.next
#=> t.rb:7:in `next': fiber called across threads (FiberError)
# from t.rb:7:in `<main>'
目次
- 特異メソッド
- インスタンスメソッド
継承しているメソッド
- Enumerableから継承しているメソッド
-
- all?
- any?
- chain
- chunk
- chunk_while
- collect
- collect_concat
- compact
- count
- cycle
- detect
- drop
- drop_while
- each_cons
- each_entry
- each_slice
- each_with_index
- each_with_object
- entries
- filter
- filter_map
- find
- find_all
- find_index
- first
- flat_map
- grep
- grep_v
- group_by
- include?
- inject
- lazy
- map
- max
- max_by
- member?
- min
- min_by
- minmax
- minmax_by
- none?
- one?
- partition
- reduce
- reject
- reverse_each
- select
- slice_after
- slice_before
- slice_when
- sort
- sort_by
- sum
- take
- take_while
- tally
- to_a
- to_h
- uniq
- zip
特異メソッド
new(size=nil) {|y| ... } -> Enumerator
[permalink][rdoc][edit]-
Enumerator オブジェクトを生成して返します。与えられたブロックは Enumerator::Yielder オブジェクトを引数として実行されます。
生成された Enumerator オブジェクトに対して each を呼ぶと、この生成時に指定されたブロックを実行し、Yielder オブジェクトに対して << メソッドが呼ばれるたびに、 each に渡されたブロックが繰り返されます。
new に渡されたブロックが終了した時点で each の繰り返しが終わります。このときのブロックの返り値が each の返り値となります。
- [PARAM] size:
- 生成する Enumerator オブジェクトの要素数を指定します。 Integer、Float::INFINITY、Proc オブジェクト、nil のいずれかを指定します。Enumerator#size の実行時に参照されます。
enum = Enumerator.new{|y| (1..10).each{|i| y << i if i % 5 == 0 } } enum.each{|i| p i } #=> 5 # 10 fib = Enumerator.new { |y| a = b = 1 loop { y << a a, b = b, a + b } } p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
produce(initial = nil) { |prev| ... } -> Enumerator
[permalink][rdoc][edit]-
与えられたブロックを呼び出し続ける、停止しない Enumerator を返します。ブロックの戻り値が、次にブロックを呼び出す時に引数として渡されます。 initial 引数が渡された場合、最初にブロックを呼び出す時にそれがブロック呼び出しの引数として渡されます。initial が渡されなかった場合は nil が渡されます。
ブロックが例外 StopIterationを投げた場合、繰り返しが終了します。
- [PARAM] initial:
- ブロックに最初に渡される値です。任意のオブジェクトを渡せます。
# 1, 2, 3, 4, ... と続く Enumerator Enumerator.produce(1, &:succ) # next を呼ぶたびランダムな数値を返す Enumerator Enumerator.produce { rand(10) } # ツリー構造の祖先ノードを列挙する Enumerator ancestors = Enumerator.produce(node) { |prev| node = prev.parent or raise StopIteration } enclosing_section = ancestors.find { |n| n.type == :section }
このメソッドは Enumerable の各メソッドと組み合わせて使うことで、 while や until ループのような処理を実装できます。例えば Enumerable#detect, Enumerable#slice_after, Enumerable#take_while などと合わせて使えるでしょう。
# 次の火曜日を返す例 require "date" Enumerator.produce(Date.today, &:succ).detect(&:tuesday?) # シンプルなレキサーの例 require "strscan" scanner = StringScanner.new("7+38/6") PATTERN = %r{\d+|[-/+*]} Enumerator.produce { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first # => ["7", "+", "38", "/", "6"]
インスタンスメソッド
self + enum -> Enumerator::Chain
[permalink][rdoc][edit]-
自身と enum 引数を続けて繰り返す Enumerator::Chain を返します。
e = (1..3).each + [4, 5] e.to_a #=> [1, 2, 3, 4, 5]
[SEE_ALSO] Enumerable#chain
each {...} -> object
[permalink][rdoc][edit]each -> self
each(*args) {...} -> object
each(*args) -> Enumerator
-
生成時のパラメータに従ってブロックを繰り返します。 *args を渡した場合は、生成時のパラメータ内引数末尾へ *args を追加した状態で繰り返します。ブロック付きで呼び出された場合は、生成時に指定したイテレータの戻り値をそのまま返します。
- [PARAM] args:
- 末尾へ追加する引数
str = "Yet Another Ruby Hacker" enum = Enumerator.new {|y| str.scan(/\w+/) {|w| y << w }} enum.each {|word| p word } # => "Yet" # "Another" # "Ruby" # "Hacker" str.scan(/\w+/) {|word| p word } # => "Yet" # "Another" # "Ruby" # "Hacker"
"Hello, world!".scan(/\w+/) # => ["Hello", "world"] "Hello, world!".to_enum(:scan, /\w+/).to_a # => ["Hello", "world"] "Hello, world!".to_enum(:scan).each(/\w+/).to_a # => ["Hello", "world"] obj = Object.new def obj.each_arg(a, b=:b, *rest) yield a yield b yield rest :method_returned end enum = obj.to_enum :each_arg, :a, :x enum.each.to_a # => [:a, :x, []] enum.each.equal?(enum) # => true enum.each { |elm| elm } # => :method_returned enum.each(:y, :z).to_a # => [:a, :x, [:y, :z]] enum.each(:y, :z).equal?(enum) # => false enum.each(:y, :z) { |elm| elm } # => :method_returned
feed(obj) -> nil
[permalink][rdoc][edit]-
Enumerator 内部の yield が返す値を設定します。
これで値を設定しなかった場合は yield は nil を返します。
この値は内部で yield された時点でクリアされます。
# (1), (2), ... (10) の順に実行される o = Object.new def o.each x = yield # (2) blocks p x # (5) => "foo" x = yield # (6) blocks p x # (8) => nil x = yield # (9) blocks p x # not reached w/o another e.next end e = o.to_enum e.next # (1) e.feed "foo" # (3) e.next # (4) e.next # (7) # (10)
- [PARAM] obj:
- Enumerator 内部の yield が返す値
- [EXCEPTION] TypeError:
- すでに値をこのメソッドでセットしている場合に発生します
next -> object
[permalink][rdoc][edit]-
「次」のオブジェクトを返します。
現在までの列挙状態に応じて「次」のオブジェクトを返し、列挙状態を1つ分進めます。列挙が既に最後へ到達している場合は、 StopIteration 例外を発生します。このとき列挙状態は変化しません。つまりもう一度 next を呼ぶと再び例外が発生します。
next メソッドによる外部列挙の状態は他のイテレータメソッドによる内部列挙には影響を与えません。ただし、 IO#each_line のようにおおもとの列挙メカニズムが副作用を伴っている場合には影響があり得ます。
- [EXCEPTION] StopIteration:
- 列挙状態が既に最後へ到達しているとき
[SEE_ALSO] Enumerator#rewind
str = "xyz" enum = str.each_byte str.bytesize.times do puts enum.next end # => 120 # 121 # 122
str = "xyz" enum = str.each_byte begin puts enum.next while true rescue StopIteration puts "iteration reached at end" end # => 120 # 121 # 122 # iteration reached at end puts enum.next #=> 再度 StopIteration 例外が発生
str = "xyz" enum = str.each_byte loop do puts enum.next end # => 120 # 121 # 122
next_values -> Array
[permalink][rdoc][edit]-
「次」のオブジェクトを配列で返します。
Enumerator#next とほぼ同様の挙動をします。終端まで到達した場合は StopIteration 例外を発生させます。
このメソッドは、
yield
と
yield nil
を区別するために使えます。
next メソッドによる外部列挙の状態は他のイテレータメソッドによる内部列挙には影響を与えません。ただし、 IO#each_line のようにおおもとの列挙メカニズムが副作用を伴っている場合には影響があり得ます。
o = Object.new def o.each yield yield 1 yield 1, 2 yield nil yield [1, 2] end e = o.to_enum p e.next_values p e.next_values p e.next_values p e.next_values p e.next_values e = o.to_enum p e.next p e.next p e.next p e.next p e.next ## yield args next_values next # yield [] nil # yield 1 [1] 1 # yield 1, 2 [1, 2] [1, 2] # yield nil [nil] nil # yield [1, 2] [[1, 2]] [1, 2]
- [EXCEPTION] StopIteration:
- 列挙状態が既に最後へ到達しているとき
[SEE_ALSO] Enumerator#next, Enumerator#peek, Enumerator#peek_values
peek -> object
[permalink][rdoc][edit]-
「次」のオブジェクトを返しますが、列挙状態を変化させません。
Enumerator#next のように現在までの列挙状態に応じて「次」のオブジェクトを返しますが、 next と異なり列挙状態を変更しません。
列挙が既に最後へ到達している場合は、StopIteration 例外を発生します。
a = [1,2,3] e = a.to_enum p e.next #=> 1 p e.peek #=> 2 p e.peek #=> 2 p e.peek #=> 2 p e.next #=> 2 p e.next #=> 3 p e.next #raises StopIteration
- [EXCEPTION] StopIteration:
- 列挙状態が既に最後へ到達しているとき
[SEE_ALSO] Enumerator#next, Enumerator#next_values, Enumerator#peek_values
peek_values -> Array
[permalink][rdoc][edit]-
Enumerator#next_values のように「次」のオブジェクトを配列で返しますが、列挙状態を変化させません。
Enumerator#next, Enumerator#next_values のように現在までの列挙状態に応じて「次」のオブジェクトを返しますが、 next と異なり列挙状態を変更しません。
列挙が既に最後へ到達している場合は、StopIteration 例外を発生します。
このメソッドは Enumerator#next_values と同様
yield
と
yield nil
を区別するために使えます。
o = Object.new def o.each yield yield 1 yield 1, 2 end e = o.to_enum p e.peek_values #=> [] e.next p e.peek_values #=> [1] p e.peek_values #=> [1] e.next p e.peek_values #=> [1, 2] e.next p e.peek_values # raises StopIteration
- [EXCEPTION] StopIteration:
- 列挙状態が既に最後へ到達しているとき
[SEE_ALSO] Enumerator#next, Enumerator#next_values, Enumerator#peek_values
rewind -> self
[permalink][rdoc][edit]-
列挙状態を巻き戻します。
next メソッドによる外部列挙の状態を最初まで巻き戻します。 self を返します。
内包するオブジェクトが rewind メソッドを持つとき(respond_to?(:rewind) に真を返すとき) は、その rewind メソッドを呼び出します。
[SEE_ALSO] Enumerator#next
str = "xyz" enum = str.each_byte p enum.next # => 120 p enum.next # => 121 enum.rewind p enum.next # => 120
size -> Integer | Float::INFINITY | nil
[permalink][rdoc][edit]-
self の要素数を返します。
要素数が無限の場合は Float::INFINITY を返します。 Enumerator.new に Proc オブジェクトを指定していた場合はその実行結果を返します。呼び出した時に要素数が不明であった場合は nil を返します。
(1..100).to_a.permutation(4).size # => 94109400 loop.size # => Float::INFINITY (1..100).drop_while.size # => nil
[SEE_ALSO] Enumerator.new
with_index(offset = 0) {|(*args), idx| ... } -> object
[permalink][rdoc][edit]with_index(offset = 0) -> Enumerator
-
生成時のパラメータに従って、要素にインデックスを添えて繰り返します。インデックスは offset から始まります。
ブロックを指定した場合の戻り値は生成時に指定したレシーバ自身です。
str = "xyz" enum = Enumerator.new {|y| str.each_byte {|b| y << b }} enum.with_index {|byte, idx| p [byte, idx] } # => [120, 0] # [121, 1] # [122, 2] require "stringio" StringIO.new("foo|bar|baz").each("|").with_index(1) {|s, i| p [s, i] } # => ["foo|", 1] # ["bar|", 2] # ["baz", 3]
生成時のパラメータに従って、要素にインデックスを添えてブロックを繰り返します。インデックスは 0 から始まります。 Enumerator#with_index は offset 引数を受け取りますが、 each_with_index は受け取りません (引数はイテレータメソッドにそのまま渡されます)。
with_object(obj) -> Enumerator
[permalink][rdoc][edit]with_object(obj) {|(*args), memo_obj| ... } -> object
-
繰り返しの各要素に obj を添えてブロックを繰り返し、obj を返り値として返します。
obj には任意のオブジェクトを渡すことができます。
ブロックが渡されなかった場合は、上で説明した繰り返しを実行し、最後に obj を返す Enumerator を返します。
# 0,1,2 と呼びだす enumeratorを作る to_three = Enumerator.new do |y| 3.times do |x| y << x end end to_three_with_string = to_three.with_object("foo") to_three_with_string.each do |x,string| puts "#{string}: #{x}" end # => foo:0 # => foo:1 # => foo:2
- [PARAM] obj:
- 繰り返しの各要素に添えて渡されるオブジェクト
[SEE_ALSO] Enumerable#each_with_object