for(;;)
文はインデックスの指定や配列の長さが必要だったり、
終了条件を間違えたりするのでなるべく使いたくないです。
for(;;)
を使わずにインデックスにアクセスするとなると、JS の場合、Array.map
やArray.forEach
など配列の反復処理、C# の場合、LINQ が思いつきます。
ただ、(個人的にですが)匿名メソッドのブロック本体に長々書くのもなんかしっくりきません。
// arr <- 配列
arr.forEach((v, i) => {
/*
* 長くていろいろやる
*
*
*/
})
(C#の場合List<T>.ForEach
が非推奨の理由もあるようです。)
そこで JS のfor...of
や C# のforeach...in
でインデックスにアクセスする方法がないかなと考えてみました。。
JavaScript の for...of
でインデックスを使う
const chars = ['J', 'a', 'v', 'a', 'S', 'c', 'r', 'i', 'p', 't']
for (const { c, i } of chars.map((c, i) => ({c, i}))) {
/*
* 長くていろいろやる
*
*
*/
console.log(`文字:${c} index:${i}`)
}
文字:J index:0
文字:a index:1
文字:v index:2
文字:a index:3
文字:S index:4
文字:c index:5
文字:r index:6
文字:i index:7
文字:p index:8
文字:t index:9
map
でインデックスと要素を持ったオブジェクトの配列を作り、それを分割代入で受け取ります。
ラムダ式の戻り値のオブジェクト{}
を囲む丸カッコ()
は必須です。
メソッド本体が1ステートメントのラムダ式でオブジェクトを返す場合、
()
で{}
を囲まないと{}
がラムダ式の本体のブロックとみなされます。
欠点としてはmap
が即時実行のため、map
とfor...of
の間で中間配列ができてしまいます。
極端に長い配列を処理する場合などメモリを圧迫する場合はやめたほうがよさそうです。
C# の foreach...in
でインデックスを使う方法
char[] chars = { 'c', 's', 'h', 'a', 'r', 'p' };
foreach (var (c, i) in chars.Select((c, i) => (c, i))) {
/*
*
* なんか長い処理
*
*/
Console.WriteLine($"文字{c} index:{i}");
}
文字c index:0
文字s index:1
文字h index:2
文字a index:3
文字r index:4
文字p index:5
LINQ のSelect
で要素とインデックスのタプルのシーケンスを作り、分割代入で受け取ってます。
LINQ は遅延実行なので、Select
とforeach
で中間配列が作られることはありません。
Select
で匿名型new { c, i }
のシーケンスを作ることもできますが、 JS と違い分割代入できません。foreach
ブロック中でx.c
のようにアクセスしなければならず、普通のfor(;;)
のほうがよさそうです。
char[] chars = { 'c', 's', 'h', 'a', 'r', 'p' };
foreach (var x in chars.Select((c, i) => new { c, i })) {
/*
*
* なんか長い処理
*
*/
Console.WriteLine($"文字{x.c} index:{x.i}");
}