234

わかりました、これは特定の言語に基づく質問ではなく、コンピューター サイエンスに関する質問ですが、map 操作と foreach 操作に違いはありますか? それとも、同じものの名前が違うだけですか?

4

9 に答える 9

311

違う。

foreach はリストを繰り返し処理し、各リスト メンバーに副作用のある操作を実行します (たとえば、各リスト メンバーをデータベースに保存するなど)。

map はリストを反復し、そのリストの各メンバーを変換し、変換されたメンバーと同じサイズの別のリストを返します (文字列のリストを大文字に変換するなど)。

于 2008-12-10T02:14:53.393 に答える
138

それらの重要な違いは、mapすべての結果をコレクションに蓄積するのに対し、foreach何も返さないことです。map通常、関数を使用して要素のコレクションを変換する場合に使用されますが、要素foreachごとにアクションを実行するだけです。

于 2008-12-10T02:15:31.193 に答える
40

つまり、foreach要素のコレクションの各要素に操作を適用するためのものであり、あるmapコレクションを別のコレクションに変換するためのものです。

と の間には 2 つの大きな違いがforeachありmapます。

  1. foreachおそらく要素を引数として受け入れることを除いて、適用される操作に概念的な制限はありません。つまり、操作は何もしないか、副作用があるか、値を返すか、値を返さない可能性があります。重要foreachなのは、要素のコレクションを反復処理し、各要素に操作を適用することです。

    map一方、操作には制限があります。操作が要素を返すことを期待しており、おそらく要素を引数として受け入れることもあります。操作は要素のmapコレクションを反復処理し、各要素に操作を適用し、最後に操作の各呼び出しの結果を別のコレクションに格納します。つまり、 はあるコレクションを別のコレクションにmap 変換します。

  2. foreach要素の単一のコレクションで動作します。これは入力コレクションです。

    map入力コレクションと出力コレクションの 2 つの要素のコレクションで動作します。

map2 つのアルゴリズムを関連付けることは間違いではありません。実際、2 つのアルゴリズムを階層的に見ることができますforeach。つまりforeach、操作でその引数を変換し、それを別のコレクションに挿入することができます。したがって、foreachアルゴリズムはアルゴリズムの抽象化、一般化mapです。実際、foreachは操作に制限がないため、これがforeach最も単純なループ メカニズムであり、ループで実行できることは何でも実行できると言えます。map、およびその他のより専門的なアルゴリズムは、表現力のためにあります。あるコレクションを別のコレクションにマップ (または変換) したい場合は、 を使用するmapよりも使用した方が意図が明確になりますforeach

この議論をさらに拡張してcopy、コレクションのクローンを作成するループというアルゴリズムを検討できます。このアルゴリズムもアルゴリズムの特殊化foreachです。要素を指定すると、同じ要素を別のコレクションに挿入する操作を定義できます。foreachその操作で使用するとcopy、明確さ、表現力、または明示性は低下しますが、実際にはアルゴリズムを実行したことになります。mapさらに考えてみましょう:は の特殊化でありcopy、それ自体がの特殊化であると言えforeachます。反復する要素のいずれかを変更mapする可能性があります。要素を変更しない場合は、単に要素をコピーし、コピーを使用しますmap意図をより明確に表現します。

言語によっては、foreachアルゴリズム自体に戻り値がある場合とない場合があります。たとえば、C++ では、foreach最初に受け取った操作を返します。アイデアは、操作には状態がある可能性があり、その操作を元に戻して、要素上でどのように進化したかを調べることができるということです。mapも、値を返す場合と返さない場合があります。C++ transform(ここでは同等map) では、たまたま出力コンテナー (コレクション) の末尾にイテレーターが返されます。Ruby では、 の戻り値mapは出力シーケンス (コレクション) です。したがって、アルゴリズムの戻り値は実際には実装の詳細です。それらの効果は、それらが返すものである場合とそうでない場合があります。

于 2010-05-28T21:52:37.243 に答える
33

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与えられた配列を歩くだけなので、配列を歩きながら自分の仕事をすることができます。

于 2013-01-29T10:56:29.540 に答える
11

最も「目に見える」違いは、マップが結果を新しいコレクションに蓄積するのに対し、foreachは実行自体に対してのみ実行されることです。

ただし、いくつかの追加の前提条件があります。マップの「目的」は新しい値のリストであるため、実行の順序は実際には重要ではありません。実際、実行環境によっては、並列コードを生成したり、メモ化を導入して繰り返し値の呼び出しを回避したり、怠惰を導入して、呼び出しをまったく回避したりします。

一方、foreachは、特に副作用のために呼び出されます。したがって、順序は重要であり、通常は並列化できません。

于 2008-12-10T02:59:54.957 に答える
11

短い答え: mapforEachは異なります。また、非公式に言えば、mapは の厳密なスーパーセットですforEach

長い答え:forEachまず、 と の 1 行の説明を考えてみましょうmap:

  • forEachすべての要素を繰り返し処理し、それぞれに対して指定された関数を呼び出します。
  • mapすべての要素を反復処理し、それぞれに対して指定された関数を呼び出し、各関数呼び出しの結果を記憶して変換された配列を生成します。

多くの言語でforEachは、単に と呼ばれることがよくありeachます。以下の説明では、JavaScript を参照用にのみ使用しています。それは本当に他の言語である可能性があります。

それでは、それぞれの機能を使ってみましょう。

使用forEach:

タスク 1:printSquares数値の配列を受け取る関数 を作成し、arrその中の各要素の 2 乗を出力します。

解決策 1:

var printSquares = function (arr) {
    arr.forEach(function (n) {
        console.log(n * n);
    });
};

使用map:

タスク 2:selfDot数値の配列を受け取り、arr各要素が の対応する要素の 2 乗である配列を返す関数を作成しますarr

余談ですが、俗語で言えば、入力配列を 2 乗しようとしています。正式には、それ自体の内積を計算しようとしています。

解決策 2:

var selfDot = function (arr) {
    return arr.map(function (n) {
        return n * n;
    });
};

mapのスーパーセットはどうforEachですか?

を使用して、タスク 1タスク 2mapの両方のタスクを解決できます。ただし、 を使用してタスク 2を解決することはできません。forEach

解決策 1では、単純に に置き換えforEachmapも、解決策は引き続き有効です。ただし、ソリューション 2では、に置き換えると、以前に機能mapforEachていたソリューションが壊れます。

forEachの観点からの実装map:

mapの優位性を実現するもう 1 つの方法は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を解決できますが、おそらくそうすべきではありません。それぞれがそのための正しい候補です。


元の答え:

map()私は@madlepの答えに大部分同意しますが、それが厳密なスーパーセットであることを指摘したいと思いforEach()ます.

はい、map()通常、新しい配列を作成するために使用されます。ただし、現在の配列を変更するためにも使用できます。

次に例を示します。

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!!"]

上記の例では、 はfor のaように都合よく設定されていました。それでいて威力を発揮する。a[i] === ii < a.lengthmap()

の公式説明はこちらmap()map()それが呼び出される配列を変更することさえあるかもしれないことに注意してください! あられmap()

これが役に立ったことを願っています。


2015 年 11 月 10 日編集: 詳細を追加。

于 2014-07-29T08:01:11.443 に答える
3

リストを使用した 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
于 2014-05-13T07:56:27.977 に答える
2

特にJavascriptについて話している場合、違いはそれmapがループ関数でforEachあり、イテレータであることです。

mapリストの各メンバーに操作を適用し、元のリストに影響を与えずに結果を新しいリストとして取得する場合に使用します。

リストの各要素に基づいて何かをしたいforEach場合に使用します。たとえば、ページに何かを追加している可能性があります。基本的に、「副作用」が欲しい場合に最適です。

その他の違い: forEach(実際には制御フロー関数であるため) 何も返さず、渡された関数はインデックスとリスト全体への参照を取得しますが、map は新しいリストを返し、現在の要素のみを渡します。

于 2008-12-10T02:19:28.393 に答える