コンピュータプログラミングにおいて、イテレータとは、コレクションの各項目に順番にアクセスできるオブジェクトです。[ 1 ] [ 2 ] [ 3 ]
コレクションは、インターフェースを介して複数のイテレータを提供することができ、それらのイテレータは、順方向や逆方向など、異なる順序でアイテムを提供する。
イテレータは、コレクション実装の基盤となる構造に基づいて実装されることが多く、イテレータの操作的意味論を実現するために、コレクションと密接に結合されていることが多い。
イテレータは、データベースカーソルと動作が似ています。
イテレータはコレクションの要素へのアクセス(要素アクセス)を提供し、内部状態を変更して次の要素へのアクセス(要素走査)を提供できます。[ 5 ]また、最初の要素の作成と初期化を提供し、すべての要素が走査されたかどうかを示します。一部のプログラミングコンテキストでは、イテレータは追加の機能を提供します。
イテレータを使用すると、コンシューマーはコレクションの内部構造から分離された状態で、コレクションの各要素を処理できます。[ 2 ]コレクションは要素を任意の方法で格納できますが、コンシューマーはシーケンスとしてアクセスできます。
オブジェクト指向プログラミングでは、イテレータクラスは通常、対応するコレクションクラスと密接に連携して設計されます。通常、コレクションクラスはイテレータを作成するためのメソッドを提供します。
ループカウンタは、ループイテレータとも呼ばれることがあります。しかし、ループカウンタは要素へのアクセス機能ではなく、要素の走査機能のみを提供します。
イテレータを実装する一つの方法は、ジェネレータと呼ばれる制限付きコルーチンを使用することです。サブルーチンとは対照的に、ジェネレータコルーチンは一度だけ値を返すのではなく、呼び出し元に複数回値を返すことができます。ほとんどのイテレータは自然にジェネレータとして表現できますが、ジェネレータは呼び出し間でローカル状態を保持するため、ツリートラバーサーのような複雑で状態を持つイテレータに特に適しています。「ジェネレータ」と「イテレータ」という用語の使用法には微妙な違いがあり、著者や言語によって異なります。[ 6 ] Pythonでは、ジェネレータはイテレータコンストラクタ、つまりイテレータを返す関数です。Pythonのステートメントを使用してフィボナッチ数のイテレータを返すPythonジェネレータの例を以下に示します。yield
from typing import Generatordef fibonacci ( limit : int ) -> Generator [ int , None , None ]: a , b = 0 , 1 for _ in range ( limit ): yield a a , b = b , a + bfor number in fibonacci ( 100 ): # ジェネレーターはイテレータを構築しますprint ( number )内部イテレータは、コレクションを走査しながら各要素に関数を適用する高階関数(多くの場合、匿名関数を引数にとる)です。例えば、Python のmap関数は、呼び出し元が定義した関数を各要素に適用します。
from typing import Iterator数字:リスト[ int ] = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]squared_digits : Iterator [ int ] = map ( lambda x : x ** 2 , digits ) # このイテレータを反復すると、0、1、4、9、16、...、81 になります。C#、C++(後のバージョン)、Delphi(後のバージョン)、Go、Java(後のバージョン)、Lua、Perl、Python、Rubyなどのオブジェクト指向言語の中には、明示的なイテレータを使わずにコレクションの要素を反復処理する固有の方法を提供するものがあります。イテレータオブジェクトは存在するかもしれませんが、ソースコードには表現されません。[ 5 ] [ 7 ]
暗黙のイテレータは、言語構文では として表されることが多いforeach。
Pythonでは、コレクションオブジェクトを直接反復処理できます。
for value in iterable : print ( value )Rubyでは、イテレーションを行うにはイテレータプロパティにアクセスする必要があります。
iterable.each do | value | puts value endこの反復スタイルは、コードが反復可能なオブジェクト(反復のすべての側面を制御する)のコンテキスト内で完全に実行され、プログラマーは各ステップで実行する操作のみを(匿名関数を使用して)提供するため、「内部反復」と呼ばれることがあります。
リスト内包表記や類似の構造をサポートする言語では、Pythonのように、結果リストの構築中に暗黙的なイテレータを使用することもあります。
名前:リスト[ str ] = [ person.name for person in roster if person.male ]暗黙的な隠蔽性は、場合によっては部分的なものに過ぎません。C ++言語には、暗黙的な反復処理のための関数テンプレートがいくつfor_each()かあります。これらの関数は、初期入力として明示的なイテレータ オブジェクトを必要としますが、後続の反復処理ではイテレータ オブジェクトがユーザーに公開されません。
イテレータは入力ストリームの便利な抽象化であり、潜在的に無限の反復可能な(ただし必ずしもインデックス可能ではない)オブジェクトを提供します。PerlやPythonなどのいくつかの言語は、ストリームをイテレータとして実装しています。Pythonでは、イテレータはデータのストリームを表すオブジェクトです。[ 8 ]ストリームの代替実装には、 AWKやsedなどのデータ駆動型言語があります。
イテレータを使用する代わりに、多くの言語では添え字演算子とループカウンタを使用して各要素にアクセスできます。インデックスはコレクションで使用できますが、イテレータの使用には次のような利点があります。[ 9 ]
現代のオブジェクト指向プログラミングでは、オブジェクト間の相互関係や操作の影響が必ずしも明確ではないため、要素を反復処理しながらコレクションを変更できる機能が必要不可欠となっています。イテレータを使用することで、こうした影響から隔離されます。しかし、この主張は鵜呑みにすべきではありません。効率上の理由から、イテレータの実装はコレクションに密接に結びついている場合が多く、基となるコレクションを変更すると、イテレータ自体が無効になってしまうからです。
メモリ内でデータが移動する可能性のあるコレクションの場合、イテレータを無効にしない唯一の方法は、コレクションが現在有効なすべてのイテレータを何らかの方法で追跡し、実行時にそれらを更新することです。特定の時点でのイテレータの数は、関連するコレクションのサイズに比べて任意に大きくなる可能性があるため、それらすべてを更新すると、コレクションの操作の複雑性保証が著しく損なわれます。
コレクションのサイズに対して更新回数を制限する別の方法として、一種のハンドル機構、つまりコレクションで更新する必要のあるコレクションの要素への間接ポインタのコレクションを使用し、イテレータがデータ要素に直接アクセスするのではなく、これらのハンドルを指すようにする方法があります。しかし、この方法は、実際のデータ要素にアクセスするために二重ポインタ操作を実行する必要があるため、イテレータのパフォーマンスに悪影響を及ぼします。これは通常望ましくありません。なぜなら、イテレータを使用する多くのアルゴリズムは、アドバンスメソッドよりもイテレータのデータアクセス操作を頻繁に呼び出すからです。したがって、非常に効率的なデータアクセスを備えたイテレータを用意することが特に重要です。
総じて言えば、これは常にセキュリティ(イテレータは常に有効である)と効率性のトレードオフです。ほとんどの場合、セキュリティの向上は、それに伴う効率性の低下に見合うものではありません。イテレータの安定性が必要な場合は、別のコレクション(例えば、ベクトルの代わりに単方向連結リスト)を使用する方が(全体的に効率が良い)良い選択肢となります。
イテレータは、その機能に応じて分類できます。以下は、イテレータのカテゴリの(網羅的ではない)リストです。[ 10 ] [ 11 ]
これらの言語で使用されるさまざまな言語またはライブラリは、イテレータ型を定義します。それらのいくつかは[ 14 ]です。
.NET Framework (つまりC #)のイテレータは「列挙子」と呼ばれ、IEnumeratorインターフェイスで表されます。[ 17 ] : 189–190、344 [ 18 ] : 53–54次の要素に進み、コレクションの末尾に達したかどうかを示すメソッドIEnumeratorを提供します。 [ 17 ] : 344 [ 18 ] : 55–56 [ 19 ] : 89現在指している要素の値を取得するプロパティ。[ 17 ] : 344 [ 18 ] : 56 [ 19 ] : 89オプションのメソッド[ 17 ] : 344は、列挙子を初期位置に戻します。列挙子は最初は最初の要素の前の特別な値を指しているため、反復を開始するには の呼び出しが必要です。MoveNext()CurrentReset()MoveNext()
GetEnumerator()列挙子は通常、インターフェースを実装するオブジェクトのメソッドを呼び出すことによって取得されますIEnumerable。[ 18 ] : 54–56 [ 19 ] : 54–56プロパティCurrentを使用して、現在指している要素の値を取得します。[ 17 ] : 344 [ 18 ] : 56 [ 19 ] : 89コンテナ クラスは通常、このインターフェースを実装します。ただし、C#のforeachステートメントは、実装していなくても、そのようなメソッドを提供する任意のオブジェクトに対して操作できます(ダック タイピング)。[ 19 ] : 89両方のインターフェースは、 .NET 2.0で汎用バージョンに拡張されました。IEnumerable
以下は、C# 2.0 におけるイテレータの簡単な使用例です。
using System ; using 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 ではジェネレータIEnumeratorもサポートされています。つまり、(またはIEnumerable)を返すように宣言されているメソッドが、オブジェクト インスタンスを返す代わりに " " ステートメントを使用して要素のシーケンスを生成すると、コンパイラによって適切なインターフェイスを実装する新しいクラスにyield return変換されます。
C言語にはイテレータは標準では存在しませんが、ポインタ演算によってある程度エミュレートできます。
以下は、intイテレータを使用したリンクリストの例です。
typedef struct LinkedList { int * value ; struct LinkedList * next ; } LinkedList ;typedef struct { LinkedList * current ; } LinkedListIterator ;LinkedListIterator list_begin ( LinkedList * head ) { LinkedListIterator it = { head }; return it ; }int * list_next ( LinkedListIterator * it ) { if ( ! it -> current ) { return NULL ; } int * value = & it -> current -> value ; it -> current = it -> current -> next ; return value ; }int main () { // ... for ( LinkedListIterator it = list_begin ( head ); ; ) { int * val = list_next ( & it ); if ( ! val ) { break ; } printf ( "%d \n " , * val ); } }C ++言語は標準ライブラリでイテレータを幅広く使用しており、許可する操作の範囲が異なるいくつかのカテゴリのイテレータを記述しています。これらには、可能性の低い順に、前方イテレータ、双方向イテレータ、ランダムアクセスイテレータが含まれます。すべての標準コンテナテンプレート型は、これらのカテゴリのいずれかのイテレータを提供します。イテレータは配列の要素へのポインタ (実際にイテレータとして使用できます) を一般化したもので、その構文はCのポインタ演算に似せて設計されています。C では、演算子*と演算子を使用してイテレータが指す要素を参照し、のようなポインタ演算演算子を使用してコンテナの走査中にイテレータを変更します。->++
イテレータを使用したトラバーサルでは、通常、可変イテレータが 1 つと、トラバーサルする範囲を区切る固定イテレータが 2 つ使用されます。++下限を上限に変換するために必要な演算子の適用回数で表した、制限イテレータ間の距離は、指定された範囲の項目の数に等しくなります。関係する異なるイテレータ値の数は、その数より 1 つ多くなります。慣例として、下限制限イテレータは範囲の最初の要素を「指し」、上限制限イテレータは範囲内のどの要素も指さず、範囲の末尾のすぐ先を指します。コンテナ全体をトラバーサルする場合、このbegin()メソッドは下限とend()上限を提供します。後者はコンテナのどの要素も参照しませんが、比較可能な有効なイテレータ値です。
以下の例は、イテレータの典型的な使用例を示しています。
import std ;std :: vectorを使用します。int main () { vector < int > items ; items . push_back ( 5 ); // 整数値 '5' をベクター 'items' に追加します。items . push_back ( 2 ); // 整数値 '2' をベクター 'items' に追加します。items . push_back ( 9 ); // 整数値 '9' をベクター 'items' に追加します。// 'items' を反復処理します。// 'it' は vector<int>::iterator 型です。for ( auto it = items . begin (), end = items . end (); it != end ; ++ it ) { // 現在のインデックスに対応する 'items' の値を表示します。std :: print ( "{}" , * it ); }// foreachループ(C++11で追加)を使用すると、// 明示的なイテレータを使用せずに同じことができます。for ( int x : items ) { // 'items'の各要素'x'の値を出力します。std :: print ( "{}" , x ); }// どちらのforループも「529」を出力します。}イテレータ型は、それと併用されるコンテナ型とは別個のものですが、両者はしばしば一緒に使用されます。イテレータのカテゴリ(およびそれに対して定義される操作)は通常、コンテナ型に依存します。たとえば、配列やベクトルはランダムアクセスイテレータを提供しますが、セット(実装としてリンク構造を使用する)は双方向イテレータのみを提供します。同じコンテナ型に複数のイテレータ型が関連付けられる場合があります。たとえば、std::vector<T>コンテナ型では、要素への(生)ポインタ(型T*)または特殊型の値を使用して走査できますstd::vector<T>::iterator。また、「逆イテレータ」用に別の型が提供されており、その操作は、通常の(順方向)走査を実行するアルゴリズムが逆イテレータで呼び出されたときに実際に逆順で走査を実行するように定義されています。ほとんどのコンテナは、別の型も提供しておりconst_iterator、その型では、指す値を変更できる操作は意図的に定義されていません。
コンテナ オブジェクトまたはその要素の範囲を単純に走査する ( をconst_iterator使用しない限り、これらの要素を変更することも含む) には、イテレータのみを使用できます。ただし、コンテナ型は、コンテナ自体の構造を変更するinsertや などのメソッドを提供することもできますerase。これらはコンテナ クラスのメソッドですが、目的の操作を指定するために 1 つ以上のイテレータ値も必要とします。複数のイテレータが同時に同じコンテナを指すことは可能ですが、構造を変更する操作によって特定のイテレータ値が無効になる場合があります (標準では、各ケースについてこれが可能かどうかが指定されています)。無効になったイテレータを使用すると、未定義の動作につながるエラーとなり、実行時システムによってこのようなエラーが通知される必要はありません。
std::for_each()暗黙的な反復処理は、標準関数テンプレート(など std::copy() ) の使用を通じて、C++でも部分的にサポートされていますstd::accumulate()。
begin使用する際は、通常はとといった既存のイテレータで初期化する必要がありますend。これらのイテレータは、反復処理が行われる範囲を定義します。ただし、反復処理が進むにつれて、明示的なイテレータ オブジェクトは後から公開されません。この例では、 の使用例を示しますfor_each。
// ItemType 要素の任意の標準コンテナタイプ。ContainerType < ItemType > c ;// コレクションの各項目を処理する関数。void processItem ( const ItemType & i ) { std :: println ( "{}" , i ); }// for-each ループ。std :: for_each ( c.begin (), c.end ( ) , processItem ) ; // std::ranges を使用: std :: ranges :: for_each ( c , processItem );同じことはstd::copy、3番目のイテレータとして値を渡すことで実現できますstd::ostream_iterator。
using std :: cout ; using std :: ostream_iterator ;std :: copy ( c.begin ( ), c.end ( ) , ostream_iterator <ItemType> ( cout , " \n " ) ); // std::rangesを使用する場合: std :: ranges :: copy ( c , ostream_iterator <ItemType> ( cout , " \ n " ) ) ;C++11以降、ラムダ関数構文を使用することで、インラインで反復する操作を指定できるようになり、名前付き関数を定義する必要がなくなりました。以下は、ラムダ関数を使用したfor-each反復の例です。
ContainerType < ItemType > c ; // ItemType 要素の標準コンテナタイプ。// ラムダ関数を使用した for-each ループ。std :: for_each ( c . begin (), c . end (), []( const ItemType & i ) -> void { std :: println ( "{}" , i ); });// std::ranges を使用する場合: std :: ranges :: for_each ( c , []( const ItemType & i ) -> void { std :: println ( "{}" , i ); });Java スタイルのイテレータ構文 ( Iterator<T>、 vs T::iterator) は、C++ では次のように実装できます。
import std ;namespace { // ヘルパー概念: イテレータを持っているかどうかtemplate < typename T > concept Has_iterator = requires { typename T :: iterator }; }template < typename Iterable > requires Has_iterator < Iterable > using Iterator = typename Iterable :: iterator ;// これで次のように呼び出すことができます:template < typename T > using Vector = std :: vector < T > ;int main () { Vector <int> v { 1 , 2 , 3 , 4 , 5 } ; for ( Iterator < Vector <int> > it = v.begin (); it != v.end ( ) ; ++ it ) { std :: println ( " { } " , * it ) ; } }Java JDK 1.2 リリースで導入されたこのjava.util.Iteratorインターフェースは、コンテナクラスの反復処理を可能にします。各クラスはおよびメソッド[ 20 ] : 294–295Iteratorを提供し、オプションで[ 20 ] : 262, 266メソッドをサポートする場合があります。イテレータは、対応するコンテナクラスによって、通常は という名前のメソッドによって作成されます。[ 21 ] [ 20 ] : 99 [ 20 ] : 217next()hasNext()remove()iterator()
このnext()メソッドはイテレータを進め、イテレータが指す値を返します。最初の要素は、最初の呼び出し時に取得されますnext()。[ 20 ] : 294–295コンテナ内のすべての要素が訪問されたかどうかを判断するには、hasNext()テスト メソッドが使用されます。[ 20 ] : 262次の例は、イテレータの簡単な使用例を示しています。
import java.util.Iterator ;Iterator iter = list.iterator ( ) ; Iterator <MyType> iter = list.iterator ( ) ; // Iterator iter = list.iterator(); ( J2SE 5.0より前) while ( iter.hasNext ( ) ) { System.out.print ( iter.next ( ) ) ; if ( iter.hasNext ( ) ) { System.out.print ( " , " ) ; } }が繰り返し呼び出されることを示すためにhasNext()、要素間にカンマを挿入しますが、最後の要素の後には挿入しません。
このアプローチでは、データ転送処理と実際のデータアクセスが適切に分離されていません。データ要素が転送処理ごとに複数回使用される必要がある場合は、一時変数に格納する必要があります。データアクセスを伴わない転送処理が必要な場合(つまり、特定のデータ要素をスキップする場合)でも、アクセス処理は実行されますが、この場合、返される値は無視されます。
対応するコレクション型の場合、remove()イテレータのメソッドは、イテレータを使用可能な状態に保ちながら、コンテナから最後にアクセスした要素を削除します。コンテナのメソッドを呼び出し(同じスレッドhasNext()から呼び出した場合も含む)、要素を追加または削除すると、イテレータは使用できなくなります。次の要素を取得しようとすると、例外がスローされます。要素が残っていない場合(以前に false が返された場合)にも、例外がスローされます。
さらに、同様のAPIをjava.util.List持つがjava.util.ListIterator、前方および後方反復が可能で、リスト内の現在のインデックスを提供し、リスト要素をその位置に設定できるものもある。
Java の J2SE 5.0 リリースでは、コレクションや配列を反復処理するための拡張 (foreach) ループをサポートするインターフェースが導入されました。はIterableをfor返すメソッドを定義Iterableします。[ 20 ] : 266拡張ループを使用すると、上記の例は次のように書き換えることができます。iterator()Iteratorfor
for ( MyType obj : list ) { System.out.print ( obj ) ; }一部のコンテナは、古いEnumerationクラス(バージョン1.0以降)も使用しています。このクラスはメソッドを提供しますhasMoreElements()がnextElement()、コンテナを変更するメソッドはありません。
Scalaでは、イテレータはコレクションと同様に豊富なメソッドセットを備えており、for ループで直接使用できます。実際、イテレータとコレクションはどちらも共通の基本特性である を継承しています。しかし、Scala コレクション ライブラリには、 、などscala.collection.TraversableOnceの豊富なメソッドセットが用意されているため、Scala でプログラミングする際にイテレータを直接扱う必要はほとんどありません。mapcollectfilter
Javaのイテレータとコレクションは、たった1行を追加するだけで、それぞれScalaのイテレータとコレクションに自動的に変換できます。
import scala.collection.JavaConversions._ファイルへの書き込み。このJavaConversionsオブジェクトは、これを行うための暗黙的な型変換を提供します。暗黙的な型変換はScalaの機能です。現在のスコープで可視である場合、関連する式に適切な場所に自身への呼び出しを自動的に挿入し、そうでなければ型チェックされない式を型チェックできるようにします。
MATLAB は、「ネイティブ」配列またはcell配列を使用した外部および内部の暗黙的反復の両方をサポートしています。外部反復の場合、トラバーサルを進めて次の要素を要求するのはユーザーの責任です。配列ストレージ構造内に要素のセットを定義し、for-loop 構造を使用して要素をトラバーサルできます。たとえば、
% 整数の配列を定義しますmyArray = [ 1 , 3 , 5 , 7 , 11 , 13 ];for n = myArray % ... n を使って何か処理を行うdisp ( n ) % コマンドウィンドウに整数を表示する endキーワードを使用して整数の配列を走査しますfor。
内部反復の場合、ユーザーがコレクションの各要素に対して実行する操作をイテレータに指定できるため、多くの組み込み演算子と MATLAB 関数がオーバーロードされ、配列の各要素に対して実行され、対応する出力配列が暗黙的に返されます。さらに、arrayfunおよびcellfun関数は、それぞれ「ネイティブ」配列および配列に対してカスタムまたはユーザー定義の操作を実行するために利用できますcell。たとえば、
function simpleFun % 整数の配列を定義しますmyArray = [ 1 , 3 , 5 , 7 , 11 , 13 ];% 各要素に対してカスタム操作を実行しますmyNewArray = arrayfun (@( a ) myCustomFun ( a ), myArray );% 結果の配列をコマンドウィンドウに表示するmyNewArrayfunction outScalar = myCustomFun ( inScalar ) % 単純に 2 を掛けるoutScalar = 2 * inScalar ;組み込み関数を使用して、配列の各要素にsimpleFunカスタムサブ関数を暗黙的に適用する主要関数を定義します。myCustomFunarrayfun
あるいは、イテレータパターンのカスタムオブジェクト指向MATLAB実装を定義することで、配列ストレージコンテナのメカニズムをユーザーから抽象化することが望ましい場合もあります。外部イテレーションをサポートするこのような実装は、MATLAB Central File Exchangeアイテム「デザインパターン: イテレータ (動作)」で示されています。これは、MATLABソフトウェアバージョン7.6 (R2008a)で導入された新しいクラス定義構文で記述されており、データ型が異なる要素セットを格納するメカニズムとして、リスト抽象データ型cell(ADT)の1次元配列実装を特徴としています。また、ループで使用するための、明示的な前方リスト走査のための機能も提供しています。hasNext()next()reset()while

PHPのforeachループはバージョン 4.0 で導入され、4.0 Beta 4 でオブジェクトを値として扱えるようになりました。[ 22 ]しかし、イテレータのサポートは、内部インターフェース[ 23 ] の導入によりPHP 5 で追加されました。[ 24 ]ループを介してオブジェクトを反復処理できるようにする PHP スクリプトで実装するための 2 つの主要なインターフェースはとです。後者は、実装クラスがすべての必要なメソッドを宣言する必要はなく、代わりにのインスタンスを返すアクセサメソッド ( ) を実装します。標準 PHP ライブラリは、特別なイテレータを操作するためのいくつかのクラスを提供します。[ 25 ] PHP は 5.5 以降、ジェネレータもサポートしています。[ 26 ]TraversableforeachIteratorIteratorAggregategetIteratorTraversable
最も簡単な実装方法は配列をラップすることです。これは型ヒントや情報隠蔽に役立ちます。
名前空間Wikipedia\Iterator ;final class ArrayIterator extends \Iterator { private array $array ;public function __construct ( array $array ) { $this -> array = $array ; }public function rewind () : void { echo 'rewinding' , PHP_EOL ; reset ( $this -> array ); }public function current () { $value = current ( $this- > array ); echo "current: { $value } " , PHP_EOL ; return $value ; }public function key () { $key = key ( $this -> array ); echo "key: { $key } " , PHP_EOL ; return $key ; }public function next () { $value = next ( $this- > array ); echo "next: { $value } " , PHP_EOL ; return $value ; }public function valid () : bool { $valid = $this -> current () !== false ; echo 'valid: ' , ( $valid ? 'true' : 'false' ), PHP_EOL ; return $valid ; } }例のクラスのすべてのメソッドは、完全な foreach ループの実行中に使用されます ( foreach ($iterator as $key => $current) {})。イテレータのメソッドは次の順序で実行されます。
$iterator->rewind()内部構造が最初から構築されることを保証する。$iterator->valid()この例ではtrueを返します。$iterator->current()返された値は に格納されます$value。$iterator->key()返された値は に格納されます$key。$iterator->next()内部構造の次の要素に進みます。$iterator->valid()falseを返し、ループは中断されます。次の例は、インターフェースを実装する PHP クラスを示しています。このクラスは、ループに返される前にデータに対して処理を行うクラスTraversableでラップすることができます。定数と組み合わせることで、 PHP スクリプトは数十億行の結果セットを非常に少ないメモリ使用量で反復処理できます。これらの機能は PHP やそのMySQLクラス実装に固有のものではありません(たとえば、クラスもインターフェースを実装しています)。IteratorIteratorforeachMYSQLI_USE_RESULTPDOStatementTraversable
mysqli_report ( MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT ); $mysqli = new \mysqli ( 'host.example.com' , 'username' , 'password' , 'database_name' );// メソッド呼び出しによって返される \mysqli_result クラスは、内部 Traversable インターフェイスを実装します。foreach ( $mysqli -> query ( 'SELECT `a`, `b`, `c` FROM `table`' , MYSQLI_USE_RESULT ) as $row ) { // 返された行(連想配列)に対して処理を実行します。}Pythonのイテレータは言語の基本的な要素であり、多くの場合、for( foreach ) 文、リスト内包表記、ジェネレータ式などで暗黙的に使用されるため、意識されることはありません。Python の標準組み込みコレクション型はすべてイテレーションをサポートしており、標準ライブラリに含まれる多くのクラスも同様です。次の例は、シーケンスに対する典型的な暗黙的イテレーションを示しています。
for value in sequence : print ( value )Pythonの辞書(連想配列の一種)は、辞書のキーが返される場合、直接反復処理することもできます。または、items()辞書のメソッドを反復処理して、対応するキーと値のペアをタプルとして取得することもできます。
for key in dictionary : value = dictionary [ key ] print ( key , value )for key , value in dictionary.items ( ) : print ( key , value )ただし、イテレータは明示的に使用および定義できます。任意の反復可能なシーケンス型またはクラスに対して、組み込み関数を使用してイテレータオブジェクトを作成します。イテレータオブジェクトは、内部的にメソッドを使用する関数iter()で反復処理できます。このメソッドは、コンテナ内の次の要素を返します。(上記の記述は Python 3.x に適用されます。Python 2.x では、メソッドは同等です。)要素がなくなると、例外が発生します。次の例は、明示的なイテレータを使用してシーケンスを反復処理する同等の方法を示しています。next()__next__()next()StopIteration
from typing import Iteratorsequence : list [ int ] = [ 1 , 2 , 3 , 4 ] it : Iterator [ int ] = iter ( sequence ) while True : try : value = it.next () # Python 2.x の場合value = next ( it ) # Python 3.xの場合except StopIteration : break print ( value )ユーザー定義クラスは、__iter__()イテレータオブジェクトを返すメソッドを定義することで、標準的な反復処理(暗黙的または明示的)をサポートできます。次に、そのイテレータオブジェクトは、次の要素を返すメソッドを定義する必要があります__next__()。
Rakuにおけるイテレータは言語の基本的な要素ですが、通常、ユーザーはイテレータについて意識する必要はありません。イテレータの使用方法はfor、ステートメントmap、、、、などによるgrepリストのインデックス付けといった反復APIによって隠蔽されています。.[$idx]
次の例は、値のコレクションに対する典型的な暗黙的な反復処理を示しています。
my @values = 1 , 2 , 3 ; for @values -> $value { say $value } # 出力: # 1 # 2 # 3Rakuハッシュは直接イテレーションすることもできます。これにより、キーと値のPairペアを持つオブジェクトが生成されます。kvハッシュに対して、キーと値をイテレーションするためのメソッド、keysハッシュのキーをイテレーションするためのメソッド、およびvaluesハッシュの値をイテレーションするためのメソッドを呼び出すことができます。
my %word-to-number = 'one' => 1 , 'two' => 2 , 'three' => 3 ; for %word-to-number -> $pair { say $pair ; } # 出力: # three => 3 # one => 1 # two => 2for %word-to-number . kv -> $key , $value { say "$key: $value" } # 出力: # three: 3 # one: 1 # two: 2for %word-to-number . keys -> $key { say "$key => " ~ %word-to-number { $key }; } # 出力: # three => 3 # one => 1 # two => 2ただし、イテレータは明示的に使用および定義できます。任意のイテラブル型には、イテレーション処理のさまざまな側面を制御するメソッドがいくつかあります。たとえば、メソッドはオブジェクトiteratorを返すように設計されておりIterator、メソッドはpull-one可能であれば次の値を生成して返すか、これ以上値を生成できない場合は番兵値IterationEndを返すように設計されています。次の例は、明示的なイテレータを使用してコレクションをイテレーションする同等の方法を示しています。
my @values = 1 , 2 , 3 ; my $it := @values . iterator ; # @values のイテレータを取得loop { my $value := $it . pull-one ; # イテレーションの次の値を取得しますlast if $value =:= IterationEnd ; # イテレーションの終わりに達したら停止しますsay $value ; } # 出力: # 1 # 2 # 3Raku のすべての反復可能な型は、Iterableロール、Iteratorロール、またはその両方で構成されます。 はIterable非常にシンプルで、iterator構成クラスが を実装するだけで済みます。 はIteratorより複雑で、 などの一連のメソッドを提供しpull-one、アイテムの追加や削除、アイテムをスキップして他のアイテムにアクセスするなど、さまざまな状況で反復をより細かく操作できます。したがって、ユーザー定義クラスは、これらのロールを組み合わせ、 およびiterator/またはpull-oneメソッドを実装することで、標準的な反復をサポートできます。
このDNAクラスはDNA鎖を表し、役割iteratorを構成することで実装しますIterable。DNA鎖は、反復処理される際にトリヌクレオチドのグループに分割されます。
部分集合Strand of Str where { . match ( /^^ <[ACGT]>+ $$/ ) and . chars %% 3 }; class DNA does Iterable { has $.chain ; method new ( Strand:D $chain ) { self . bless: : $chain } } メソッドiterator ( DNA:D: ){ $.chain . comb . rotate ( 3 ). iterator } }; DNA用。新しい( 'ガタガタ' ) { 。言う } # 出力: # (GAT) # (TAC) # (ATA)say DNA.new ( ' GATTACATA' ). map (*. join ) .join ( ' -' ); # 出力: # GAT-TAC-ATAこのRepeaterクラスは、Iterableと両方のIterator役割を構成します。
class Repeater does Iterable does Iterator { has Any $.item is required ; has Int $.times is required ; has Int $!count = 1 ; multi method new ( $item , $times ) { self . bless: : $item , : $times ; } メソッドiterator { self } メソッドpull-one (--> Mu ){ if $!count <= $!times { $!count += 1 ; return $!item } else { return IterationEnd } } } Repeater.new ( " Hello " , 3 ) { 。言う } # 出力: # Hello # Hello # HelloRuby ではイテレータの実装方法が大きく異なります。すべてのイテレーションは、コンテナ メソッドにコールバック クロージャを渡すことによって行われます。このようにして、Ruby は基本的なイテレーションだけでなく、関数マッピング、フィルタ、リデューシングなどのさまざまなイテレーション パターンも実装しています。Ruby は基本的なイテレーション メソッドの代替構文もサポートしておりeach、次の 3 つの例は同等です。
( 0 ... 42 ) .each do | n | puts n end...そして...
for n in 0 ... 42 puts n endまたはさらに短い
42回| n |を実行するとnが終了Ruby では、上記のように、固定リストを反復処理するために、Enumeratorリストを使用して#nextメソッドを呼び出すか、リストに対して for each を実行することもできます。
Rustは標準ライブラリ全体で外部イテレータを使用しており、forループ内でも外部イテレータが暗黙的に呼び出され、next()イテレータが消費されるまでそのメソッドが実行されます。最も基本的なforループは、例えば次のようRangeな型を反復処理します。
for i in 0 .. 42 { println! ( "{}" , i ); } // 0から41までの数字を出力します具体的には、forループは値のメソッドを呼び出しinto_iter()、そのメソッドはイテレータを返します。イテレータは、要素をループに渡します。ループfor(またはイテレータを使用する任意のメソッド)は、メソッドが値next()を返すまで続行されますNone(要素を返すイテレーションはSome(T)値を返します。ここで、Tは要素の型です)。
標準ライブラリが提供するすべてのコレクションは、このIntoIteratorトレイトを実装しています(つまり、into_iter()メソッドを定義しています)。イテレータ自体もこのIteratorトレイトを実装しており、そのためにはnext()メソッドを定義する必要があります。さらに、このトレイトを実装する型には、自身を返すIteratorメソッドの実装が自動的に提供されますIntoIterator。
イテレータは、特性によって自動的に提供されるメソッドとして、さまざまなアダプタ(map()、、、など)をサポートします。filter()skip()take()Iterator
ユーザーは、特性を実装する型を作成することで、カスタムイテレータを作成できますIterator。カスタムコレクションはIntoIterator特性を実装し、要素に関連付けられたイテレータ型を返すことで、forループ内で直接使用できるようになります。以下に、Fibonacci型がカスタムの無制限イテレータを実装する例を示します。
struct Fibonacci ( u64 , u64 );impl Fibonacci { pub fn new () -> Self { Self ( 0 , 1 ) } }impl Iterator for Fibonacci { type Item = u64 ;fn next ( & mut self ) -> Option < Self :: Item > { let next = self . 0 ; self . 0 = self . 1 ; self . 1 = self . 0 + next ;いくつか(次へ)} }fn main () { let fib = Fibonacci :: new ( ); for n in fib.skip ( 1 ) .step_by ( 2 ) .take ( 4 ) { println! ( "{n}" ); } // 1、2、5、13 が出力されます}![]()
ユーザー定義イテレータは通常、コード参照の形式をとり、実行されるとリスト内の次の項目を計算して返します。イテレータがリストの末尾に達すると、合意された値を返します。
イテレータは、抽象データ構造の内部表現を明らかにすることなくループできるようにする構成要素として導入されました。
イテレータは、より大きなアイテムのコンテナの一部であるアイテムを指すものと考えることができます。
イテレータは、反復ロジックを持つクラスのメンバ関数によって実装されます。外部イテレータは、反復ロジックを持つオブジェクトにアタッチできる別のクラスによって実装されます。外部イテレータの利点は、既存のオブジェクトまたは同じオブジェクトで複数のイテレータを同時にアクティブにできることです。
{{cite web}}: CS1 maint: bot: 元の URL の状態が不明です (リンク)著者によってはイテレータという用語を使用し、ジェネレータという用語を使用する者もいる。両者の間に微妙な違いがある。
{{cite web}}: CS1 maint: bot: 元の URL の状態が不明です (リンク)インデックスは、ランダムアクセス (つまり、指定された位置にある要素への直接アクセス) を (効率的に) サポートするコンテナにのみ使用できます。イテレータは、より一般的な概念です。イテレータは、リンクされたリスト、ファイル、およびその他の多くのデータ構造を効率的に走査します。多くの場合、より効率的なコードの生成につながります。
{{cite web}}: CS1 maint: bot: 元の URL の状態が不明です (リンク){{cite web}}: CS1 maint: bot: 元の URL の状態が不明です (リンク)•イテレータ型 iterator および const_iterator は、前方イテレータ カテゴリに属します。