イテレータ

イテレータとは、プログラミング言語において配列やそれに類似する集合的データ構造の各要素に対する繰り返し処理の抽象化である。実際のプログラミング言語では、オブジェクトまたは文法などとして現れる。JISでは反復子と翻訳されている。

ジェネレータ  の記事も参照のこと。

1. 種類
-----

1.1. 内部イテレータ
------------

2. 各言語における例
-----------

2.1. C++
--------

C++では、STLが外部イテレータの枠組みを定義している。この枠組みはポインタと構文上の互換性を持つよう定められているため、ポインタを用いるコードと同等のコードでイテレータを使用することができる。

template void printall { for  { std::cout << *first << std::endl; } }

C++ではイテレータの種類によって使用できる演算子に違いがある。例えば、std::vectorコンテナのイテレータのような「ランダムアクセスイテレータ」と、std::listコンテナのイテレータのような「双方向イテレータ」は、共にインクリメント/デクリメント演算子を用いて直後/直前の要素を指すことができる。しかし、任意の幅の加算/減算はランダムアクセスイテレータでのみ定義されている。ランダムアクセスイテレータは双方向イテレータの一種だが、イテレータの進行操作は定数時間で実行できることが要件として定められている。std::listコンテナの要素は、前後の要素へのポインタしか保持していないためシーケンシャルアクセスしかできず、イテレータの進行操作が定数時間で実行できないため、ランダムアクセスイテレータをサポートすることができない。

もともとC++のイテレータはテンプレートを利用した静的ダックタイピングによるものであり、各イテレータの要件定義は規格で文書化されていたものの、言語構文としてはサポートされていなかった。しかし、C++20ではコンセプト  をサポートしたことにより、std::random_access_iteratorやstd::bidirectional_iteratorなどの形で満たすべき要件をコードとして書き下すことが可能になった。

2.2. Delphi
-----------

Delphiでは、バージョン2005よりfor-in構文によるイテレータがある。ユーザーによるイテレータはMoveNextメソッドやCurrentプロパティを任意のクラス等に実装することで定義でき、型に厳格なPascal系言語ながらこれらを実装するだけでfor-inにより認識されるというダックタイピングにも似た仕組みとなっている。

for item in items do Writeln;

2.3. Java
---------

Javaでは、name=java.util.Iteratorインターフェイス族を実装するオブジェクトを外部イテレータとして扱うことができる。Java 1.5以降のIteratorはジェネリクスに対応しているJavaのジェネリクスは型消去による実装であり、型システムの上ではIteratorもIteratorも同じ型である。}}。

import java.util.*; // ...

final List list = new ArrayList; // Java 1.5 以降は以下のように書くこともできる。 //final List list = new ArrayList; // Java 1.7 以降は以下のように書くこともできる。 //final List list = new ArrayList<>;

list.add; list.add); list.add);

final Iterator it = list.iterator; // Java 1.5 以降は以下のように書くこともできる。 //final Iterator it = list.iterator;

while ) { final Object obj = it.next; System.out.println); }<WtXmlEndTag />

Java 1.5以降では、name=java.lang.Iterableインターフェイスを実装すると、拡張for文の対象にすることができる。 // java.util.List は Iterable を実装している。 for  { System.out.println); }

2.4. Perl
---------

Perlには、foreach、each といった繰り返しのキーワードがある。 他に、Tie機能でユーザーデータに対するイテレータを定義できる。

foreachを使った例。配列・リストに対する反復。foreach my $element{ print $element, " "; }<WtXmlEndTag />

eachを使った例。ハッシュに対する反復。while = each %hash){ print "$key=$value "; }<WtXmlEndTag />

2.5. PHP
--------

PHPではIteratorインターフェイスを実装することにより、任意のイテレータを定義することができる。Iteratorインターフェイスを実装したオブジェクトをforeachやwhileで使用することで反復を行うことができる。 また、配列はIteratorインターフェイスを暗黙に実装する。

foreachを使った例。配列・連想配列・オブジェクト等に対し全く同じように使用できる。foreach { print $key . "=" . $value . " "; }<WtXmlEndTag />

2.6. Python
-----------

Pythonは次の要素を返す__next__メソッドを持つオブジェクトを外部イテレータとして使う。コンテナオブジェクトの__iter__メソッドがイテレータを返す。

通常のプログラミングでは、obj.__iter__のように直接呼ぶのではなく、組込み関数iterを使ってiterのようにする。同様に、通常の用法で呼ぶことを前提とした場合は__next__ではなくnextを使う。for文はイテレータが使える場合はイテレータを使うが、そうでないコンテナオブジェクトに対しては直接、__getitem__メソッドにより要素を取得し繰返しを実行する。

cont = iteratable_container

イテレータを直接使うit = iter while 1: try: print it.next except StopIteration:

要素が残っていないならば、
nextはStopIteration例外を発生させるbreak

for文で使うfor element in cont: print element<WtXmlEndTag />

また、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

it = fruit_generator print) print) print) print) # この行で StopIteration 例外になる<WtXmlEndTag />

2.7. Ruby
---------

RubyではEnumerableが、eachなどのイテレートするメソッドを持っている内部イテレータである。each}}メソッド呼出しに { ... } という書式で「ブロック」を書くと、その中の手続きが繰返し実行される。

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<WtXmlEndTag />

2.8. .NET言語
-----------

C#、VB.NETなどの.NET Frameworkに準拠する.NET言語において、反復子  は値の順序付き列を産出  する文のブロックを意味する。これを反復子ブロック  とも呼ぶ。また、コレクションに対する列挙操作を行なう機能を提供するための媒介インターフェイスを列挙子  と呼び、IEnumeratorインターフェイスによって表す。IEnumeratorインターフェイスはMoveNextメソッドを定義しており、このメソッドを使用することによりコレクション中の次の要素に進むと同時に、コレクションの末尾に到達するかどうかを判定する。Currentプロパティを使用することによってコレクション内部の要素を取得する。イテレータを最初の要素に戻す方法としてResetメソッドが定義されるが、常に使用可能であるとは限らない。

列挙子を得るには通例IEnumerableインターフェイスを実装するオブジェクトのGetEnumeratorメソッドを呼び出す。一般的にコレクション クラスはこのIEnumerableインターフェイスを実装する。GetEnumeratorを明示的に呼び出さず、foreach文を代わりに使用することもできる。IEnumeratorおよびIEnumerableインターフェイスは、.NET 2.0でジェネリック版  として拡張された。

2.8.1. C# 2.0
-------------

// 明示的な使い方 IEnumerator iter = list.GetEnumerator; while ) { Console.WriteLine; }

// 暗黙的な使い方 foreach  { Console.WriteLine; }<WtXmlEndTag />

2.8.2. Visual Basic 8.0
-----------------------

' 明示的な使い方 Dim iter As IEnumerator = list.GetEnumerator Do While iter.MoveNext Console.WriteLine Loop

' 暗黙的な使い方 For Each value As MyType In list Console.WriteLine Next value<WtXmlEndTag />

2.8.3. yield文
-------------

C# 2.0およびVB.NET 11は反復子の形でジェネレータ  をサポートする。ジェネレータはIEnumeratorまたはIEnumerableを返すよう宣言されたメソッドであるが、オブジェクトインスタンスを返す代わりに要素のシーケンスを生成するためのyield returnステートメントを使用する。yieldステートメントを用いて記述されたジェネレータはコンパイラによって、適切なインターフェイスを実装する新しいクラスに変換される。ただし、ジェネレータはIEnumerator.Resetメソッドをサポートしない。

// 反復子の記述例。 static IEnumerable MyIteratorMethod { yield return 1; yield return -1; yield return 0; yield break; }

IEnumerable elements = MyIteratorMethod; // この時点では、まだメソッドの本体は実行されない。

// 列挙によりメソッドの本体が順次「遅延実行」される。 foreach  { Console.WriteLine; }<WtXmlEndTag />

Shared Iterator Function MyIteratorMethod As IEnumerable Yield 1 Yield -1 Yield 0 Return End Function

Dim elements As IEnumerable = MyIteratorMethod

For Each element As Integer In elements Console.WriteLine Next<WtXmlEndTag />

2.9. D言語
--------

D言語では、標準ライブラリにレンジ  というイテレータが定義されており、規定されたインターフェイスを持っているオブジェクトなら何でもレンジとして扱うことができる。

foreach  writeln;

3. 脚注
-----

3.1. 注釈
-------

3.2. 出典
-------

4. 関連項目
-------

ループ 
Foreach文
Iterator パターン
コンテナ 
カーソル 
fgetc