わかりました、これは特定の言語に基づいた質問というよりも、コンピューターサイエンスの質問ですが、マップ操作とforeach操作に違いはありますか?または、それらは同じものに対して単に異なる名前ですか?
違う。
foreachはリストを反復処理し、副作用を伴う操作を各リストメンバーに適用します(たとえば、各メンバーをデータベースに保存するなど)
mapはリストを反復処理し、そのリストの各メンバーを変換し、変換されたメンバーと同じサイズの別のリストを返します(文字列のリストを大文字に変換するなど)
それらの重要な違いは、map
はすべての結果をコレクションに蓄積するのに対して、foreach
は何も返さないことです。 map
は通常、関数を使用して要素のコレクションを変換するときに使用されますが、foreach
は各要素に対してアクションを実行するだけです。
要するに、foreach
は要素のコレクションの各要素に操作を適用するためのものであり、map
はコレクションを別のコレクションに変換するためのものです。
foreach
とmap
には2つの重要な違いがあります。
foreach
は、おそらく要素を引数として受け入れることを除いて、適用する操作に概念的な制限はありません。つまり、操作は何もしない、副作用がある、値を返す、または値を返さない場合があります。 foreach
が気にするのは、要素のコレクションを反復処理し、各要素に操作を適用することです。
一方、map
には、操作に制限があります。操作が要素を返すことを期待し、おそらく要素を引数として受け入れることもあります。 map
操作は要素のコレクションを反復処理し、各要素に操作を適用し、最後に操作の各呼び出しの結果を別のコレクションに保存します。言い換えると、map
transformsあるコレクションから別のコレクションへ。
foreach
は、単一の要素コレクションで機能します。これは入力コレクションです。
map
は、入力コレクションと出力コレクションの2つの要素コレクションで機能します。
2つのアルゴリズムを関連付けることは間違いではありません。実際、2つを階層的に表示できます。ここで、map
はforeach
の特殊化です。つまり、foreach
を使用して、操作で引数を変換し、別のコレクションに挿入できます。したがって、foreach
アルゴリズムは、map
アルゴリズムの抽象化、一般化です。実際、foreach
にはその動作に制限がないため、foreach
が最も単純なループメカニズムであり、ループでできることは何でも実行できます。 map
、および他のより特殊なアルゴリズムは、表現力を高めるためにあります。あるコレクションを別のコレクションにマッピング(または変換)する場合、map
を使用する場合よりもforeach
を使用する場合の方が明確です。
この議論をさらに拡張して、copy
アルゴリズム、つまりコレクションを複製するループを検討することができます。このアルゴリズムもforeach
アルゴリズムの特殊化です。要素を指定すると、その同じ要素を別のコレクションに挿入する操作を定義できます。その操作でforeach
を使用すると、明確さ、表現力、または明示性は低下しますが、実際にはcopy
アルゴリズムを実行しました。さらに詳しく見てみましょう:map
はcopy
の特殊化であり、それ自体がforeach
の特殊化であると言えます。 map
はchange反復する要素のいずれかです。 map
がどの要素も変更しない場合は、単にコピー要素であり、copyを使用すると意図がより明確に表現されます。
foreach
アルゴリズム自体は、言語に応じて戻り値を持つ場合と持たない場合があります。たとえば、C++では、foreach
は最初に受け取った操作を返します。考えは、操作に状態がある場合があり、その操作を元に戻して、要素上でどのように進化したかを検査することです。 map
も、値を返す場合と返さない場合があります。 C++では、transform
(ここではmap
と同等)は、イテレータを出力コンテナ(コレクション)の最後に返すことがあります。 Rubyでは、map
の戻り値は出力シーケンス(コレクション)です。したがって、アルゴリズムの戻り値は実際には実装の詳細です。それらの効果は、それらが返すものである場合とそうでない場合があります。
Array.protototype.map
メソッドとArray.protototype.forEach
はどちらも非常に似ています。次のコードを実行します。 http://labs.codecademy.com/bw1/6#:workspace
var arr = [1, 2, 3, 4, 5];
arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
console.log();
arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
それらは正確な結果を与える
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
ここでは、マップおよびforEachメソッドからの戻り値の結果を単純に割り当てました。
var arr = [1, 2, 3, 4, 5];
var ar1 = arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar1);
console.log();
var ar2 = arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar2);
console.log();
結果はトリッキーになりました!
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
[ 1, 2, 3, 4, 5 ]
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
undefined
Array.prototype.map
は配列を返しますが、Array.prototype.forEach
は返しません。したがって、mapメソッドに渡されたコールバック関数内で返された配列を操作して、それを返すことができます。
Array.prototype.forEach
は指定された配列のみをウォークスルーするため、アレイをウォークしている間に何かを行うことができます。
簡単な答え:map
とforEach
は異なります。また、非公式に言えば、map
はforEach
の厳密なスーパーセットです。
長答:最初に、forEach
とmap
の1行の説明を考えてみましょう。
forEach
は、すべての要素を反復処理し、それぞれに対して指定された関数を呼び出します。map
は、すべての要素を反復処理し、それぞれに対して提供された関数を呼び出し、各関数呼び出しの結果を記憶することにより、変換された配列を生成します。多くの言語では、forEach
は単にeach
と呼ばれます。以下の説明では、参照のみにJavaScriptを使用しています。本当に他の言語でもかまいません。
それでは、これらの各機能を使用してみましょう。
forEach
を使用:タスク1:関数printSquares
を作成します。これは、数値の配列arr
を受け入れ、各要素の平方を出力しますそれ。
ソリューション1:
var printSquares = function (arr) {
arr.forEach(function (n) {
console.log(n * n);
});
};
map
を使用:タスク2:関数selfDot
を記述します。これは、数値の配列arr
を受け入れ、各要素がarr
の対応する要素の二乗。
余談ですが、ここでは、スラングで、入力配列を二乗しようとしています。正式に言えば、それ自体との内積を計算しようとしています。
ソリューション2:
var selfDot = function (arr) {
return arr.map(function (n) {
return n * n;
});
};
map
はどのようにforEach
のスーパーセットですか?map
を使用して、両方のタスクタスク1およびタスク2。ただし、forEach
を使用してタスク2を解決することはできません。
ソリューション1で、単にforEach
をmap
に置き換えるだけでも、ソリューションは有効です。ただし、ソリューション2では、map
をforEach
に置き換えると、以前に機能していたソリューションが破損します。
forEach
に関してmap
を実装する:map
の優位性を実現する別の方法は、forEach
の観点からmap
を実装することです。私たちは優れたプログラマーなので、名前空間の汚染にふけることはありません。 forEach
、単にeach
と呼びます。
Array.prototype.each = function (func) {
this.map(func);
};
prototype
のナンセンスが気に入らなければ、ここに行きます:
var each = function (arr, func) {
arr.map(func); // Or map(arr, func);
};
forEach
は存在するのでしょうか?答えは効率です。配列を別の配列に変換することに興味がない場合、変換された配列を計算する必要があるのはなぜですか?ダンプするだけですか?もちろん違います!変換が必要ない場合は、変換を実行しないでください。
したがって、mapを使用してTask 1を解決できますが、おそらくそうすべきではありません。それぞれがそのための正しい候補です。
@madlepの答えにはほぼ同意しますが、map()
はforEach()
のstrict super-setであることを指摘したいと思います。
はい、通常、map()
を使用して新しい配列を作成します。ただし、alsoを使用して現在の配列を変更することもできます。
以下に例を示します。
var a = [0, 1, 2, 3, 4], b = null;
b = a.map(function (x) { a[x] = 'What!!'; return x*x; });
console.log(b); // logs [0, 1, 4, 9, 16]
console.log(a); // logs ["What!!", "What!!", "What!!", "What!!", "What!!"]
上記の例では、a
はa[i] === i
がi < a.length
になるように便利に設定されていました。それでも、map()
の力を示しています。
これはmap()
の公式の説明です 。 map()
は、呼び出される配列を変更することさえあることに注意してください!あられmap()
。
これが役に立てば幸いです。
編集2015年11月10日:詳細を追加。
最も「目に見える」違いは、マップが結果を新しいコレクションに蓄積するのに対し、foreachは実行自体に対してのみ行われることです。
ただし、いくつかの追加の仮定があります。マップの「目的」は値の新しいリストであるため、実行の順序は実際には重要ではありません。実際、一部の実行環境では並列コードが生成されます。また、繰り返し値の呼び出しを回避するためのメモ化や、一部の呼び出しを回避するための遅延が導入されています。
一方、foreachは副作用のために特別に呼び出されます。したがって、順序は重要であり、通常は並列化できません。
リストを使用したScalaの例を次に示します。mapはリストを返し、foreachは何も返しません。
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
したがって、mapは、関数fを各リスト要素に適用した結果のリストを返します。
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list map (x => x * 2)
res0: List[Int] = List(2, 4, 6)
Foreachは各要素にfを適用するだけです:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
特にJavascriptについて話している場合、違いはmap
がループ関数であり、forEach
が反復子であるということです。
リストの各メンバーに操作を適用し、元のリストに影響を与えずに結果を新しいリストとして取得する場合は、map
を使用します。
リストの各要素に基づいてdoを行う場合は、forEach
を使用します。たとえば、ページに物事を追加する場合があります。基本的に、「副作用」が必要な場合に最適です。
その他の違い:forEach
は(実際には制御フロー関数であるため)何も返さず、渡された関数はインデックスとリスト全体への参照を取得しますが、mapは新しいリストを返し、現在の要素のみを渡します。
ForEachは、何も返さずにRDDの各要素にdbなどへの書き込みなどの関数を適用しようとします。
ただし、map()
はrddの要素に何らかの関数を適用し、rddを返します。したがって、以下のメソッドを実行すると、line3で失敗しませんが、foreachを適用した後にrddを収集するときに失敗し、エラーがスローされます
ファイル「<stdin>」、5行目、<module>
AttributeError: 'NoneType'オブジェクトには属性 'collect'がありません
nums = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
num2 = nums.map(lambda x: x+2)
print ("num2",num2.collect())
num3 = nums.foreach(lambda x : x*x)
print ("num3",num3.collect())