for文はもう使わない?
forおじさんと揶揄されていますがJS、phpなどではすでに使わないほうがいいのでしょうか?
極力whileを使って、どうしても使わざるおえないときのみ使うべきなのでしょうか?
ただwhileでできない事はまったくないと聞くので一切使わない手もありますね。
読みにくいからでしょう?
皆さんありがとうございます。
沢山ご回答いただいたのでここで一括にお返事させてもらいます。
まだfor文を使うのは有りなのですね。
単純な繰り返し、繰り返しの回数が決まっていない場合は、
最速はwhileをとりあえず使い。
何回繰り返すか、決まっている場合でwhileでは無理のある場合のみforで良い。
という感じですかね。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/20 10:25
![guest](/img/icon/icnUserSample.jpg)
回答11件
0
「JS、phpなど」とありますので、JavaScriptとPHP以外についてそれぞれ取り上げてみました。
###Go
Goにはwhile
がありません。無限ループや単純な条件ループはwhile
の代わりにfor
を使う必要があります。
###Ruby
Rubyのfor
は使う理由がありません。ブロックを作らないというただ一つの違いを除きeach
呼び出しと同じだからです。私は(検証などを除いて)Rubyでfor
を書いたことは一度もありません。
###Java
拡張for文がまだまだ使えると思います。StreamのforEach
というのもありますが、ラムダ式に制限が多い(finalまたは暗黙finalなローカル変数しか使えないとか、検査例外を非検査例外にする必要があるだとか)ので使いやすいとは言えないです。
###C++
範囲ベースfor
文が非常に使えます。for_each
ってあまり使った覚えが無いです。こちらもラムダ式を扱うのが面倒だからかもしれません。
###C
そもそもfor_each
等の代替となる関数や仕組みが標準で用意されていません。配列の要素を辿る場合は、0からnまでの数値を増やしながらの順次処理にするしかないのですが、while
で代用すると非常に読みにくくなってしまいます。ただ、null終端文字列などは最後が\0
であることを利用して、while
を使った方が良い場合があります(strcpyの実装例等)。
###Python
for
を禁止にされると便利な内包表記まで使えなくなってしまいます。for
を使わないというのはあり得ないです。
###Haskell
Haskellにはfor
がありません。
投稿2017/09/20 11:05
総合スコア21735
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
PHPでやるなら9割の状況でforeach。
なぜならばPHPがHTMLの動的生成がゴールになることが多い以上、配列を触る状況が殆どだから。
whileやfor文は何度動作するのかを常に把握し続ける必要がある、
1回多くループが回っても、1回少なくループが回っても駄目。
状態変数が増えてソースコードが読みづらくなった結果、不具合が発生しやすくなる。
(特に九九の掛け算や多次元配列を操ると一気にネストが深くなり状態変数も一気に増える)
配列操作に限定されるけどforeachを使えば何度ループが回るかが一目。
配列のアイテムが既に取り出せた状態から始まるから状態変数の管理も不要といい事ずくめ。
またforやwhileと比較してもほぼ等速なのでforeach以外を使う意味がない。
残り僅かのケースは速度がどうしても遅いからチューニングする事になって、
無からわざわざrange(1, 10)
みたいな事をしてforeachを使うのは賛否両論があるから、for ($i = 0; $i < 10; $i++)
はわざわざ避ける必要はない。
fopen、feofみたいな低級関数(低俗という意味ではなく、マシン語に近いという意味ね)を使う場合はwhileがよく使われる。
まぁ、PHPは多くの配列操作用のビルトイン関数が揃っているから、
筋の良い関数を使ってワンライナーで書ける場合はforeachすら不要。
下記の関数が一例(他にもあるかも)
yambejpさんの一例は賛否あるだろうけど個人的には好き。
PHPならではの良さを考えると富豪的で分かりやすい手法はあって良いと思う。
JavaScriptもDOM操作の元になる配列を作ったり、Ajax通信でPHPからJSONを貰ってきて解析する事が多い。
やはり配列の操作がメインになるから純粋な配列やオブジェクトを用意して、for (;;)
やwhileを避けて開発するべきだね。
(こねくり回した不順な配列やオブジェクトはthink49さんが言うようにfor...in等でprototypeが紛れ込む罠がある)
JavaScriptでやる場合for...ofやfor...inを使っていくとPHPのforeachと同じ事が出来る。
ただ、for...ofは古いブラウザに非対応だし、for...inはkeyが来るのでPHPのforeach程汎用的に使えるわけじゃない。
yubaさんの言うようにリスト操作用のメソッドを利用していくのがベースになる。
高速なライブラリや関数を作るならforやwhileを使いまくりになると思うけどね。
もちろんその分のテストもすべきだし、ライブラリの中身は可読性ガン無視で良いわけでもないから考えて使うのは重要だと思う。
追記部分への対応
何回繰り返すか、決まっている場合でwhileでは無理のある場合のみforで良い。
という感じですかね。
for文の速度に関しての言及は特に無かったけど、別にwhileだから速いということは無い。
言語にもよるけど、コンパイラが解釈して同じマシン語に変換されるので同じ速度になる可能性もある。
もっと言うと、for文で1箇所にまとめた方が良いマシン語に変換されて速く動作する可能性すらある。
本当に速度を気にするならちゃんとコンパイラの実装まで確認した方がいい。
(私は確認したこと無いけど、100万回程ループ回して比較しているベンチマーク記事とか結構あるからね)
なんとなくwhileの方がやってること少ないから速そうだからと、何でもかんでもwhileで書くのはやめて、まずは可読性の事を考えよう。
投稿2017/09/20 09:48
編集2017/09/23 00:34総合スコア21177
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
for 文
JavaScriptにおいては、古い環境(PC)でも安定して高速に動作するので、今でも for
は使います。
ただ、実際のところ、3つめのエリアは使わなくても書けるので while
で書くことが多いですが。
JavaScript
1for (var i = 0, len = array.length; i < len; ++i) { // ++i のエリアが要らない 2 array[i] = 1; 3} 4 5// ↓ 6 7for (var i = 0, len = array.length; i < len; ) { // 3つめのエリアが空欄で無駄 8 array[i++] = 1; 9} 10 11// ↓ 12 13var var i = 0, len = array.length; 14while (i < len) { // while で十分 15 array[i++] = 1; 16}
ただし、for
文で配列を走査する場合、値の存在しない要素も undefined
と評価してしまう問題があります。
JavaScript
1var array = [,,2]; 2 3for (let value of array) { 4 console.log(value); // undefined -> undefined -> 2 5} 6 7for (var i = 0, len = array.length; i < len; ++i) { 8 console.log(array[i]); // undefined -> undefined -> 2 9} 10 11array.forEach(v => console.log(v)); // 2 12 13for (var i = 0, len = array.length; i < len; ++i) { 14 if (array.hasOwnProperty(i)) { 15 console.log(array[i]); // 2 16 } 17}
逆にいえば、Array#forEach
はプロパティの存在確認という手順を for 文よりも多くしている為、パフォーマンス効率が悪いと判断する事も出来ます。
値の存在しない配列に遭遇する機会がどれだけあるかは分かりませんが、この性質は留意しておく必要があります。
for 文以外の構文、関数
一般に for
文が非推奨とされるのは、同一スコープ上に存在する変数の数が多くなり、保守性が低下するからです。
const
や let
を使えば解決する問題ですが、スコープを分ける場合には他にも選択肢があります。
Array.prototype.forEach
,Array.prototype.filter
等のArray.prototype
系メソッド (ES5)for-of
(ES6)Map.prototype.forEach
(ES6)Object.keys()
(ES5)Object.values()
,Object.entries()
(ES8)
しかしながら、Array.prototype.filter
は配列全体を検索して新しい配列を生成して返す関数であり、目的を見据えて実装しないとパフォーマンスが低下する懸念があります。
その処理は破壊的で良いのか、非破壊的でなければならないのか、は良く考えて実装する必要があります。
私は for
文は、まだ現役だと思っていますよ。
使用頻度は低下しているかもしれませんが、選択肢の一つとして持っておくのは悪くないと思います。
Re: amebatv さん
投稿2017/09/20 11:58
編集2017/09/20 12:07総合スコア18182
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
ループ回数が最初から分かっている場合なら、for を使う。
ループ回数が不定なら while, do-while を使う。
リスト構造などに対する全体処理なら foreach なり集合関数を使う。
結局のところ適材適所であって、for だからというだけで否定するのは賢いとは言えませんね。
リストからデータを削除していくような場合だと、foreach 系は使えず(foreach の最中に、元の集合を追加・削除するのは禁忌事項です)、for を逆順で回して処理する、なんて使い方もしますが。
※別の集合に入れていく手もありますが、メモリを食うしガベージコレクションが汚くなるしで、やりたかないですねえ
投稿2017/09/20 10:15
総合スコア13703
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
![退会済みユーザー](https://ddjkaamml8q8x.cloudfront.net/profileImages/deletedUser/icnUserSample.jpeg)
退会済みユーザー
2017/09/22 06:30
2017/09/22 06:50
2017/09/22 14:39
![guest](/img/icon/icnUserSample.jpg)
0
比較的初心者ですけど、回答してみます。
処理内容によるのではないでしょうか?
例えばリストや配列などを回すときにfor
やwhile
を使うのは確かに良くないと思います。無駄な繰り返し変数が必要だからです。
forEach
やmap
等を使うのが今は一般的でしょう。
しかしリストや配列を使わずに処理を繰り返したいならばそれこそfor
を使う方が読みやすいでしょうし、特定条件(終了するイベントなどでしょうか?)を元に処理を続けるかを判断するのにはwhile
が適していると思います。
またfor
の代用がwhile
に務まるかと言われるとそうではない気がします。
「どんな処理にも」for
を使うのは古いと思いますが、中にはfor
が適した処理もあります。それが言いたかったことです。
投稿2017/09/20 09:48
総合スコア2043
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/20 10:00
2017/09/20 11:00 編集
2017/09/20 13:36
2017/09/21 02:39
![guest](/img/icon/icnUserSample.jpg)
0
前提は配列操作なのでしょうか?
であれば、miyabi-sun さんの回答がしっくりきます。
ただ、なんでもかんでも同じループ使うのか?というのは、疑問があり。
回答している方、それぞれできたら聞きたいのが・・・
無限ループ(そもそも、やらないという回答もあり)
n回リトライ(わざわざ、n要素数の配列を作る?)
とか、記載してくれると勉強になります。
投稿2017/09/20 10:14
総合スコア4820
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/20 12:58
![退会済みユーザー](https://ddjkaamml8q8x.cloudfront.net/profileImages/deletedUser/icnUserSample.jpeg)
退会済みユーザー
2017/09/20 13:53
![guest](/img/icon/icnUserSample.jpg)
0
forもwhileも副作用があるので使わないで良いです。再帰処理で対応出来ますし。
もちろん、それらを使っても良いですが。(phpの場合は分かりません。)
投稿2017/09/20 09:35
編集2017/09/21 00:45![退会済みユーザー](https://ddjkaamml8q8x.cloudfront.net/profileImages/deletedUser/icnUserSample.jpeg)
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
![退会済みユーザー](https://ddjkaamml8q8x.cloudfront.net/profileImages/deletedUser/icnUserSample.jpeg)
退会済みユーザー
2017/09/20 09:48
![guest](/img/icon/icnUserSample.jpg)
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。