Foreach文
foreach文またはfor-each文(フォーイーチぶん)とは、プログラミング言語においてリストや連想配列などの「コレクション」と呼ばれるデータ構造の各要素に対して与えられた文の実行を繰り返すループ文である。foreach文はしばしばfor文の一部という位置付けにあるが、for文と異なり要素の参照順序が定義されないことがある。
処理の流れ
編集Perlでの構文は以下のようになる。
foreach 変数 (リスト) { 文 }
このループはだいたい次のような手順で実行される。
- 変数にリストの中のある要素への参照を代入する。
- 文を実行する。
- 全要素を参照し終わっていない場合は、変数に「次の要素」を代入して文の実行へ戻る。
ここで、線形リストや配列など要素の順序が決まっているものは、通常その順序でループが実行されるので、この場合以下とほぼ同様である。
for ( my $i = 0; $i < @list; $i++ ) { 変数 = $list[$i]; 文 }
ただし、ハッシュテーブルによって実装された連想配列など、要素の順序関係が決められていない「コレクション」の場合、その参照される順序は不定である。
文法
編集awk
編集for (変数 in 配列) { 文 }
C#
編集foreach (型 変数 in コレクション) { 文 }
コレクションは配列のほか、IEnumerable
もしくはIEnumerable<T>
を実装したオブジェクトでもよい。実際の要件は特定のインターフェイスを実装していることではなく、GetEnumerator()
という名前のメソッドを実装してさえいれば何でもよい[1]。
C++
編集C++11にて、範囲ベースの for ループが言語仕様として追加されている。
for (型 変数 : コレクション) { 文 }
上記で「コレクション」と記した箇所には、配列のほか、std::vector
やstd::array
のような標準ライブラリにおいてコンテナに分類される各種のオブジェクトなども使用できる。
そのほか、1998年の標準規格化当初からC++標準ライブラリにfor_eachアルゴリズム(関数テンプレート)が存在する。
関数オブジェクト = std::for_each( 先頭イテレータ, 末尾イテレータ, 関数オブジェクト );
C++11では、C#同様に型推論およびラムダ式を組み合わせることで、上記の構文が威力を発揮するようになる。
なお、C++/CLI言語およびMicrosoft Visual C++ 2005以降の独自拡張機能では、for each
文を使用できるが、不安定で正常に動作しない場合がある[要説明]。また、これはC++11における範囲ベース for ループとは互換性がない。
for each (変数 in コレクション) { 文 }
D
編集式を評価し、その結果は静的配列、動的配列、連想配列、構造体、クラスでなければいけない。式部分が配列である場合は、変数は複数宣言することができる。
foreach (変数 ; 式) { 文 }
Go
編集Goのforeachループは、配列、スライス、文字列、マップ、チャンネルのループに使用できる[2]。
2値形式を使用すると、インデックス/キー(最初の要素)と値(2番目の要素)を得ることができる。
for index, value := range コレクション { // インデックスと値に何かをする }
単値のフォームを使って、index/key(最初の要素)を取得する。
for index := range コレクション { // インデックスに何かをする }
Java
編集Java 5で導入された拡張for文 (enhanced for statement) [3][4]がforeach文に相当する。コレクションにはjava.util.Collection
など、java.lang.Iterable
を実装する式を配置することができる。
for (型 変数 : コレクション) { 文 }
また、文ではなくメソッドであるが
コレクション.forEach( 変数 -> { 文 } )
の様に .forEach メソッドにラムダ関数を渡しコレクションの要素に対し反復処理を行うことができる[5]。
JavaScript, ActionScript
編集オブジェクトの反復処理にはfor-in文を用いる。変数にはプロパティ名(連想配列で言うキー)が代入されるので、プロパティの値は式 オブジェクト[変数]
で取得する。
for (const 変数 in オブジェクト) { 文 }
JavaScriptのfor-in文は、ユーザー定義のプロパティについて、プロトタイプチェーンをさかのぼって反復処理を行う。このため、特に配列に対してfor-in文を用いると、他の言語とは異なる挙動をすることがある。
const array = new Array(3); let output = ""; for (const key in array) { output += key + " "; } // このとき array.length === 3 であるが、 // array にユーザー側から配列要素を定義していないので、 // output === "" である。 // 配列もオブジェクトなので、数値以外のプロパティを設定できる。 array.foo = "foo" output = ""; for (const key in array) { output += key + " "; } // このとき output === "foo " である。 // オブジェクトに新しいインスタンスメソッドを追加してみる。 Object.prototype.myMethod = function () {}; output = ""; for (const key in array) { output += key + " "; } // 配列もオブジェクトなので、このとき output === "foo myMethod " である。 // なおもちろん、この時点でも array.length === 3 である。
ECMA-262第5版 (JavaScript 1.6, ActionScript 3.0) からは、ArrayインスタンスにforEachメソッドが追加された。このメソッドは本項で説明されているforeach文と同様に配列の要素を反復して文を実行する[6]。
array.forEach(function (変数) { 文 });
ECMA-262第6版 (ECMAScript 2015) からは、配列などのiterableオブジェクトの値で反復処理をするfor-of文も導入された[7]。
for (変数 of オブジェクト) { 文 }
Perl
編集foreachキーワードを使用する。Perlにおいて、forとforeachは互いに交換可能である[8]。
foreach 変数 (コレクション) { 文 }
PHP
編集foreach (配列 as 変数) { 文 }
foreach (配列 as 変数1 => 変数2) { 文 }
前者の場合、処理手順は他の言語と同様だが、後者の場合、変数1に配列の添字が、変数2に要素が代入される。
Python
編集Pythonにおけるfor文は、Cのようにカウンタ変数の増減や評価を直接記述することはできず、他の言語におけるforeach文と同等である。
- 基本的なイテレータブルコレクションへの反復処理
- :
for 変数 in イテレータブルコレクション : 文
Pythonのタプル代入は、forループでも利用でき、辞書オブジェクトの(キー、値)ペアを反復処理することも容易にできる。
- 辞書オブジェクトへの反復処理
- :
for key, value in 辞書オブジェクト.items(): 文
for ... in
がPythonの唯一のforループなので、他の言語で見られるカウンターループ相当には、組み込み関数 range
を用いる。
- カウンターループ
- :
for i in range(len(seq)): # seq[i] への処理
組み込み関数 enumerate
関数を用いると、添字と要素の対でシーケンスへの繰り返しができる。この場合もタプル代入を利用する。
- 添字と要素の対で反復処理
- :
for i, item in enumerate(seq): 文
Pythonのfor文はelseを伴うことができす。
- breakとelse
- :
for 変数 in イテレータブルコレクション : 文1 if 条件式: 文2 break 文3 else 文4
- 条件式が真であった場合、文2が実行された後のbreak文で、for文のループを中断する。
- elseのブロック文4は、for文のループを完走した場合のみ実行され、breakで中断した場合は実行されない。
Ruby
編集for 変数 in コレクション 文 end
これは以下のイテレータ構文と、変数のスコープを除いて等価である。
コレクション.each do |変数| 文 end
なお、Rubyに関してはもっぱら後者の構文が好まれる傾向にある。
Rust
編集for
ループは for <pattern> in <expression> { /* optional statements */ }
という構造を持つ。
これは暗黙のうちに式の IntoIterator::into_iter
メソッドを呼び出し、結果として得られる値を使用する。
これは Iterator
trait を実装しなければならない。
式がそれ自体イテレータである場合、それは implementation of IntoIterator
for all Iterator
を通して for
ループによって直接使用され、イテレータは変更されずに返される。
ループは、ループ本体を実行する前に、イテレータの Iterator::next
メソッドを呼び出す。
Iterator::next
が Some(_)
を返した場合、内部の値が pattern に割り当てられ、ループ本体が実行される。
None
を返した場合、ループは終了する。
let mut numbers = vec![1, 2, 3]; // Immutable reference: for number in &numbers { // calls IntoIterator::into_iter(&numbers) println!("{}", number); } for square in numbers.iter().map(|x| x * x) { // numbers.iter().map(|x| x * x) implements Iterator println!("{}", square); } // Mutable reference: for number in &mut numbers { // calls IntoIterator::into_iter(&mut numbers) *number *= 2; } // prints "[2, 4, 6]": println!("{:?}", numbers); // Consumes the Vec and creates an Iterator: for number in numbers { // calls IntoIterator::into_iter(numbers) // ... } // Errors with "borrow of moved value": // println!("{:?}", numbers);
Smalltalk
編集コレクション do: [ :変数 | 文 ].
SmalltakはLispの影響を受けており、言語構文として反復構文が存在しない。そのため、#do:セレクターとブロックオブジェクトを使ったメッセージで表現する。上記ではメッセージを受け取るレシーバーをコレクションと表記しているが、#do:は#do:を実装しCollectionあるいはIterableを継承していれば良く、入力ストリームや高々1回しか実行しないオブジェクト、無限数列などもレシーバーとして指定できる。また、イテレーターのような反復状態を持つ専用のクラスが必要なく#do:のメソッドだけで完結するため、C++のような方式に比べ実装が単純になっている。またフィルターも容易であり、フィルター用のクラスも多数存在する。#do:は列挙プロトコルに属しており、#do:を実装しCollectionあるいはIterableを継承したオブジェクトは、#select:, #collect:, #detect:, #inject:into:といったその他の列挙プロトコルが同時に使えるようになる。
- 戻り値を返さない。(Smalltalkの制約上、正確にはselfを返す)
- #do:の引数としてValueAdapter (#value:を送ることができるオブジェクト) を指定する。(ブロックはValueAdapterの一種)
- 引数として指定したValueAdapterが0回以上の反復に対応している。
(1 to: 100) do: [ :each | 文 ].
例えば一定回数反復したい場合も#do:を使い、上記のようになる。
Smalltalkは後発の無名関数を備えたオブジェクト指向言語に広く影響を与えており、Ruby、ECMAScript、Java、C#も同様のライブラリを備えつつある[要説明]。
Visual Basic
編集For Each 変数 In コレクション 文 Next 変数
PowerShell
編集foreach (変数 in コレクション) { 文 }
HSP
編集foreach 変数 文 loop
なでしこ
編集(リスト)を反復。 文
変数は「それ」に代入される。
シェルスクリプト
編集cshではforeachと書き、shではforと書く。実用上リストの部分にはワイルドカードを含むファイル列を書くことが多い。
csh系
foreach 変数 ( リスト ) 文 end
sh系
for 変数 in リスト do 文 done
番外編
編集PL/SQL
編集OracleのPL/SQLにも、カーソルというForEachと似たような機能が実装されている。 カーソルは用途が限定されているため、番外編として紹介する。
SELECT文でとってきた複数レコードを、カーソルを使って順繰り出力するPL/SQL文を示す。
DECLARE CURSOR C IS SELECT * FROM TBL1 WHERE TBL1.FIELD1 >= 100; BEGIN FOR D IN C LOOP DBMS_OUTPUT.PUT_LINE(D.FIELD1 || ' ' || D.FIELD2 || ' ' || D.FIELD3); END LOOP; END;
参照
編集- ^ foreach - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
- ^ “Range Clause”. The Go Programming Language Specification. The Go Programming Language. 2021年9月29日閲覧。
- ^ An enhanced for loop for the Java™ Programming Language | The Java Community Process(SM) Program - communityprocess - jsr
- ^ The for Statement (The Java™ Tutorials > Learning the Java Language > Language Basics)
- ^ インタフェースIterable<T>
- ^ Array.prototype.forEach() - JavaScript | MDN
- ^ for...of - JavaScript | MDN
- ^ perlsyn - Perl syntax - Perldoc Browser