ネタです
はじめに
Javaに限らず,プログラムを書いていると何重ものforループを書かなければならない時が発生します.
例. int型三次元配列の全ての要素を1にしたい.
final int n = 10;
final int[][][] cube = new int[n][n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
cube[i][j][k] = 1;
}
}
}
しかし,このようなループはネストが深くなったり行数が無駄に増えるため,プログラムの保守性が悪化する原因となります.
そこで,多重forループを一重にする方法を考えます.
forループの構文
問題を解決するために,まずはforループの構文を確認して行きます.
Eclipse JDTによると,for文は以下のような構成になっています
for (
[ ForInit ];
[ Expression ] ;
[ ForUpdate ] )
Statement
また,ForInitとForUpdateは以下のように定義されています.
ForInit:
Expression { , Expression }
ForUpdate:
Expression { , Expression }
ForInit
とForUpdate
は複数の式を指定できるので,ForInit
に多重forループで必要となるそれぞれの変数の宣言をForUpdate
で変数の更新を書くことができそうです.
やってみた
それでは実際に一重のforループにしていきます.
初期化式
先ほどの例だと,必要な変数はi,j,k
の三つなので,初期化式は
int i = 0, j = 0, k = 0
で大丈夫そうです.
条件式
次に(終了)条件式ですが,今回の場合はj,k
の値に関係なく,一番外側のループを制御するi
について
i < n
と書くことができます.
更新式
最後に更新式について考えていきます.
ループの内側を制御する変数から順番(k -> j -> i
)に考えていきます.
まずk
についてですが,ループの度にインクリメントし,なおかつkの値がnになるタイミングで0になればよいので
k = (k + 1) % n
と書けます.
次にj
についてですが,j
の更新のタイミングはk
が0になったタイミングであり,それ以外では値は変わらないため
j = k == 0 ? (j + 1) % n : j
となります.
最後にi
ですが,更新のタイミングはk == 0 && j == 0
なので
i = j == 0 && k == 0 ? i + 1 : i
です.
結果
これまでの結果を統合すると以下のように書き換えられます.
final int n = 10;
final int[][][] cube = new int[n][n][n];
for (int i = 0, j = 0, k = 0; i < n; k = (k + 1) % n, j = k == 0 ? (j + 1) % n : j, i = j == 0 && k == 0 ? i + 1 : i) {
cube[i][j][k] = 1;
}
最初の三重ループのコードに比べるとネストが減り,すっきりした印象を受けたのではないでしょうか?
おわりに
今回は多重forループを一重ループに変換する方法を紹介しました.
ぜひこれを参考にしてコードの可読性を高めてください!