JavaScriptで
reduce()と
再帰を理解
するのに問題があったので、最初にそれらを自分自身に説明するためにこの記事を書きました(ちょっと、見て、これは再帰です!)。 これらの概念には、アップルパイの作成といくつかの類似点があります。 私の例が有用で食欲をそそるのを実感してください。
ネストされた配列を含む配列が与えられます:
var arr = [1, [2], [3, [[4]]]]
その結果、次のものを取得します。
var flat = [1, 2, 3, 4]
forループとifステートメントを使用します。
作業しなければならないネストされた配列の最大数がわかっている場合(この例では4つあります)、配列の各要素を反復処理するためのforループが適切であり、この要素自体が配列であるかどうかを確認するifステートメントなど...
function flatten() { var flat = []; for (var i=0; i<arr.length; i++) { if (Array.isArray(arr[i])) { for (var ii=0; ii<arr[i].length; ii++) { if (Array.isArray(arr[i][ii])) { for (var iii=0; iii<arr[i][ii].length; iii++) { for (var iiii=0; iiii<arr[i][ii][iii].length; iiii++) { if (Array.isArray(arr[i][ii][iii])) { flat.push(arr[i][ii][iii][iiii]); } else { flat.push(arr[i][ii][iii]); } } } } else { flat.push(arr[i][ii]); } } } else { flat.push(arr[i]); } } }
これは基本的には機能しますが、読むことと理解することの両方にとって困難です。 さらに、これはネストされた配列の数がわかっている場合にのみ機能します。 そして一般的に、この混乱全体をデバッグすることがどのようになるか想像できます(今でも不必要に余分なものを追加しているようです)。
reduceを使用します。
幸いなことに、JavaScriptには、コードをよりわかりやすく簡単にするためのメソッドがいくつかあります。 そのような方法の1つがreduce()です。 そして、それはすべて次のようになります。
var flat = arr.reduce(function(done,curr){ return done.concat(curr); }, []);
結果ははるかに少ないコードですが、ネストされた配列(この例では1つ)をスキップします。 reduce()がどのように連携するかを段階的に見て、それを修正するために何をするかを見てみましょう。
Array.prototype.reduce()
reduce()メソッドは、関数をアキュムレーターと配列の各値(左から右へ)に適用し、単一の値に減らします。 ( MDN )
見た目ほど難しくありません。 reduce()について、開発者の作業の範囲外のものとして話しましょう。 このアダムに会いましょう。 Adamの主な機能は、リンゴをヒープから取り出し、洗い、バスケットに1つずつ入れることです。 光沢のあるリンゴのこのバスケットは、おいしいアップルパイになるように設計されています。 これは非常に重要な仕事です。
リンゴ+人間の努力=パイ。 フォーミュラとアップル人間のパイのレシピを混同しないでください、それはそれほど美味しくありません。上記の例では、リンゴの束がarr配列です。 バスケットは完成した変数、バッテリーです。 最初の完了値は空の配列で、[]がreduce()の最後のパラメーターであるため、空の配列です。 Adamが現在洗濯しているリンゴは(現在から)通貨です。 Adamは現在のリンゴの洗浄が終了するとすぐにバスケットに入れます(これは.concat()で行います)。 りんごの山が終わると、アダムはきれいなりんごのバスケットを私たちに渡し、猫の家に帰ります。
reduce()を使用すると、ネストされた配列に再帰的にアクセスできます。
さて、アダムの仕事の結果によると、純粋なリンゴのバスケットがあり、すべてが素晴らしいようです。 ただし、これらのネストされた配列を処理する必要があります。 類推に戻って、いくつかのリンゴは非常に良かったので、販売時に別々の箱に詰められていたとします。 各箱の中には、リンゴが多く、リンゴを含む箱が多く、小さな箱があります。
愛らしい、少し歪んだリンゴは、ただ愛され、食べられたいと思っています 。
これが、リンゴ処理関数/ Adamに必要なものです。
- リンゴの束がリンゴの束である場合、山からリンゴを取ります。
- あなたが取ったものがリンゴであれば、それを洗ってバスケットに入れます。
- 取ったものが箱なら、箱を開けてください。 リンゴが箱に入っている場合は、手順2に進みます。
- ボックスに別のボックスがある場合は、手順3に進みます。
- リンゴの山からこれ以上ないとき、バスケットをください。
- リンゴの束がまったくリンゴの束ではない場合、それらが何であれ、それを返します。
reduce()を使用した再帰関数は次のようになります。
function flatten(arr) { if (Array.isArray(arr)) { return arr.reduce(function(done,curr){ return done.concat(flatten(curr)); }, []); } else { return arr; } }
忍耐と私はすべてを説明します。
再帰
関数のアクションには、それ自体への呼び出しが伴います。 再帰は、より小さい問題を含む問題を解決するために使用されます。 再帰関数は通常、2つの属性を取ります。ベースレジスタ(再帰の終わり)または再帰レジスタ(再帰が続く)です。 ( MDN )
上記のコードを見ると、flatten()が2回表示されていることがわかります。 彼が最初に現れるとき、彼はアダムにたくさんのリンゴをどうするかを伝えます。 二度目に、彼は彼が今持っているものをどうするかを彼に伝え、これがリンゴであるか、リンゴでないかを指示する。 これらの命令は、私たちが始めた元の命令の繰り返しであり、これが再帰であることに注意してください。
明確にするために、すべてを行ごとに分析します。
- function flatten(arr){ -共通の関数を呼び出し、引数arrを取ることを示します。
- if(Array.isArray(arr)){ -受信したものが配列かどうかを確認します。
- return arr.reduce(function(done、curr){ -前の行がtrueを返し、引数が配列に渡される場合、 reduce()に渡します-これは再帰レジスタです。
- return done.concat(flatten(curr)); -予期しないプロットのひねり! 呼び出す関数は、私たちが今いる関数そのものです。 要するに、上からやり直します。
- }、[]); -reduce関数に空のバッテリー(完了)で開始し、関数が返すものをその中に正確に入れるように指示します。
- } else { -これにより、2行目がfalseを返す場合、つまり引数が配列でない場合が許可されます。
- return arr; -arrが等しくないものを返します(おそらくきれいなリンゴ)。 これはすでにベースレジスタにあり、再帰から抜け出します。
- } -elseブロックの完了。
- } -一般機能の完了。
これで完了です! 24行の4層ネストforループから、より簡潔で簡潔な9行の再帰的ソリューションに移行しました。 リデュースと再帰は、最初は理解するのが難しいように思えるかもしれませんが、それらを理解するとすぐに将来多くの労力を節約できる貴重なツールです。
そして、私たちのアイドル開発者であるアダムについて心配する必要はありません。 この記事の後、彼は非常に注目され、AIベースのアップルパイ工場を開設しました。 彼はとても喜んでいます。
AdamのAppleについての冗談を期待している場合は、+ 1してください。
この記事では、明らかなことを述べるリスクがあります。 しかし、質問は尋ねられるべきです:「誰に明白ですか?」
初めて記事の翻訳を行います。記事の修正、修正、欠点の指摘に感謝します。