イテレータ

イテレータ（英語: iterator）とは、プログラミング言語において配列やそれに類似する集合的データ構造（コレクションあるいはコンテナ）の各要素に対する繰り返し処理の抽象化である。実際のプログラミング言語では、オブジェクトまたは文法などとして現れる。JISでは反復子（はんぷくし）と翻訳されている。 ジェネレータ (プログラミング) の記事も参照のこと。 C++では、STLが外部イテレータの枠組みを定義している。この枠組みはポインタと互換性を持つよう定められているため、ポインタを用いてイテレータを構成することができる。 template<typename InputIterator> void printall(InputIterator first, InputIterator last) { for(; first != last; ++first) { std::cout << *first << std::endl; } } なお、イテレータの種類によって用いることのできる演算子に違いがある。例えば、std::vectorコンテナのイテレータ（ランダムアクセスイテレータ）とstd::listコンテナのイテレータ（双方向イテレータ）は共にインクリメント/デクリメントを用いて次/前の要素を指すことができるが、任意の加算/減算は前者でのみ定義されている。これはstd::listコンテナの要素が、前後の要素へのポインタしか保持していないためシーケンシャルアクセスしかできず、n 個先の要素への移動が定数時間で実行できないからである。 Delphiでは、バージョン2005よりfor-in構文によるイテレータがある。ユーザーによるイテレータはMoveNextメソッドやCurrentプロパティを任意のクラス等に実装することで定義でき、型に厳格なPascal系言語ながらこれらを実装するだけでfor-inにより認識されるというダックタイピングにも似た仕組みとなっている。 for item in items do Writeln(item); Javaでは、Iteratorインターフェイス族を実装するオブジェクトが外部イテレータとなる。 Iterator it = list.iterator(); while (it.hasNext()) { Object val = it.next(); System.out.println(val.toString()); } Perlには、foreach、each といった繰り返しのキーワードがある。 他に、Tie機能 (変数操作のオーバーロード) でユーザーデータに対するイテレータを定義できる。 # foreachを使った例。配列・リストに対する反復 foreach my $element(@array){ print $element, "\n"; } # eachを使った例。ハッシュ(連想配列)に対する反復 while(my($key, $value) = each %hash){ print "$key=$value\n"; } PHPではIteratorインターフェイスを実装することにより、任意のイテレータを定義することができ、foreach、while といったキーワードでイテレータを簡単に利用することができる。 また、大抵のオブジェクトにはあらかじめイテレータが実装されている。 # foreachを使った例。配列・連想配列・オブジェクト等に対し全く同じように使用できる。 foreach ( $elements as $key=>$value ){ print $key . "=" . $value . " \n"; } Pythonは次の要素を返す__next__()メソッドを持つオブジェクトを外部イテレータとして使う。コンテナオブジェクトの__iter__()メソッドがイテレータを返す。（便宜上、イテレータの__iter__()は自身を返す） 通常のプログラミングでは、obj.__iter__()のように直接呼ぶのではなく、組込み関数iterを使ってiter(obj)のようにする。同様に、通常の用法で呼ぶことを前提とした場合は__next__()ではなくnext()を使う。for文（Foreach文）はイテレータが使える場合はイテレータを使うが、そうでないコンテナオブジェクトに対しては直接、__getitem__()メソッドにより要素を取得し繰返しを実行する。 Pythonはfor文を使うから内部イテレータである、と考える者がいるようだが誤解である。 cont = iteratable_container() # イテレータを直接使う it = iter(cont) while 1: try: print it.next() except StopIteration: # 要素が残っていないならば、 # next()はStopIteration例外を発生させる break # for文で使う for element in cont: print element また、Pythonには一種のコルーチンを記述できるジェネレータもある。ジェネレータはイテレータを返す関数で、yield文により、__next__()で実行される手続きを次々と記述できる。 def fruit_generator(): yield 'banana' # 最初の __next__() によりここまで実行され 'banana' を返す yield 'apple' # 次の __next__() によりここまで実行され 'apple' を返す yield 'orange' # 3回目の __next__() によりここまで実行され 'orange' を返す for fruit in fruit_generator(): print(fruit) it = fruit_generator() print(next(it)) print(next(it)) print(next(it)) print(next(it)) # この行で StopIteration 例外になる Rubyでは、Arrayなどのコンテナオブジェクトが、eachなどのイテレートするメソッドを持っている内部イテレータである。メソッド呼出しの直後に { ... } という書式で「ブロック」を書くと、その中の手続きが繰返し実行される。「ブロック付きメソッド」（あるいは、「ブロック付きメソッド呼び出し」）と言い、これをイテレータとも呼ぶ。 ブロックを付けて呼ばれたメソッド中でyieldを実行すると、ブロックの中の手続きが実行される。Pythonのジェネレータと同じyieldというキーワードで、コードの見た目も似たものになるが、具体的な働きは全く異なることに注意。 class MyObj def my123 yield 1 yield 2 yield 3 end end arr = ["a", "b", "c"] arr.each do |x| p x end obj = MyObj.new obj.my123 do |x| p x end C#、VB.NETなどの.NET Frameworkに準拠する.NET言語において、反復子 (iterator) は値の順序付き列を産出 (yield) する文のブロック（狭義ではyield文を含むメソッド）を意味する。これを反復子ブロック (iterator block) とも呼ぶ。また、コレクションに対する列挙操作を行なう機能を提供するための媒介インターフェイスを列挙子 (enumerator) と呼び、IEnumeratorインターフェイスによって表す。IEnumeratorインターフェイスはMoveNext()メソッドを定義しており、このメソッドを使用することによりコレクション中の次の要素に進むと同時に、コレクションの末尾に到達するかどうかを判定する。Currentプロパティを使用することによってコレクション内部の要素を取得する。コレクションの最初の要素に戻す方法としてReset()メソッドを使用する。 列挙子を得るには通例IEnumerableインターフェイスを実装するオブジェクトのGetEnumerator()メソッドを呼び出す。一般的にコレクション クラスはこのIEnumerableインターフェイスを実装する。GetEnumerator()を明示的に呼び出さず、foreach文を代わりに使用することもできる（GetEnumerator()はコンパイラによって暗黙的に呼び出される）。IEnumeratorおよびIEnumerableインターフェイスは、.NET 2.0でジェネリック版 (System.Collections.Generic) として拡張された。 // 明示的な使い方 IEnumerator<MyType> iter = list.GetEnumerator(); while (iter.MoveNext()) Console.WriteLine(iter.Current); // 暗黙的な使い方 foreach (MyType value in list) Console.WriteLine(value); C# 2.0およびVB.NET 11は反復子の形でジェネレータ (generator) をサポートする。ジェネレータはIEnumeratorまたはIEnumerableを返すよう宣言されたメソッドであるが、オブジェクトインスタンスを返す代わりに要素のシーケンスを生成するためのyield returnステートメントを使用する。yieldステートメントを用いて記述されたジェネレータはコンパイラによって、適切なインターフェイスを実装する新しいクラスに変換される。ただし、ジェネレータ（反復子）はIEnumerator.Reset()メソッドをサポートしない。 // 反復子の記述例。 static IEnumerable<int> MyIteratorMethod() { yield return 1; yield return -1; yield return 0; yield break; } IEnumerable<int> elements = MyIteratorMethod(); // この時点では、まだメソッドの本体は実行されない。 // 列挙によりメソッドの本体が順次「遅延実行」される。 foreach (int element in elements) Console.WriteLine(element); ' 明示的な使い方 Dim iter As IEnumerator(Of MyType) = list.GetEnumerator() Do While iter.MoveNext() Console.WriteLine(iter.Current) Loop ' 暗黙的な使い方 For Each value As MyType In list Console.WriteLine(value) Next value D言語では、標準ライブラリにレンジ (Range) というイテレータが定義されており、規定されたインターフェイスを持っているオブジェクトなら何でもレンジとして扱うことができる。 foreach (item; range) writeln(item); ^ JISC 日本工業標準調査会 JISX3014「プログラム言語C++」、JISX3015「プログラム言語C#」など。 ^ 繰り返し子（くりかえしし）という訳もあるが一般的ではない。「Rubyプログラミング入門」著者: 原信一郎、出版: オーム社、p.197。 ^ JISX3015「プログラム言語C#」p.64より引用。 ^ 反復子 (C#) | Microsoft Docs ^ yield (C# リファレンス) | Microsoft Docs ^ yield (C# リファレンス) ^ IEnumerable・IEnumerator - Programming/.NET Framework/列挙操作と列挙子 - 総武ソフトウェア推進所 ループ (プログラミング) Foreach文 Iterator パターン コンテナ (データ型) カーソル (データベース) fgetc