web-dev-qa-db-fra.com

Existe-t-il une différence entre foreach et map?

Ok, c’est plus une question d’informatique qu’une question basée sur une langue particulière, mais existe-t-il une différence entre une opération de carte et une opération de foreach? Ou sont-ils simplement des noms différents pour la même chose?

213
Robert Gould

Différent.

foreach effectue une itération sur une liste et applique une opération avec des effets secondaires à chaque membre de la liste (par exemple, en enregistrant chaque élément dans la base de données)

map itère sur une liste, transforme chaque membre de cette liste et renvoie une autre liste de même taille avec les membres transformés (telle que la conversion d'une liste de chaînes en majuscules)

288
madlep

La différence importante entre eux est que map accumule tous les résultats dans une collection, alors que foreach ne renvoie rien. map est généralement utilisé lorsque vous souhaitez transformer une collection d'éléments avec une fonction, alors que foreach exécute simplement une action pour chaque élément.

119
Henk

En bref, foreach sert à appliquer une opération sur chaque élément d’une collection d’éléments, tandis que map sert à transformer une collection en une autre.

Il y a deux différences significatives entre foreach et map.

  1. foreach n'a pas de restrictions conceptuelles sur l'opération appliquée, à part peut-être accepter un élément comme argument. En d'autres termes, l'opération peut ne rien faire, avoir un effet secondaire, renvoyer une valeur ou ne pas renvoyer de valeur. Tout ce que foreach veut, c’est de parcourir une collection d’éléments et d’appliquer l’opération sur chaque élément.

    map, d'autre part, a une restriction sur l'opération: elle s'attend à ce que l'opération renvoie un élément et accepte probablement également un élément en tant qu'argument. L'opération map effectue une itération sur une collection d'éléments, applique l'opération à chaque élément et stocke le résultat de chaque appel de l'opération dans une autre collection. En d'autres termes, le maptransforme une collection en une autre.

  2. foreach fonctionne avec une seule collection d'éléments. Ceci est la collection d'entrée.

    map fonctionne avec deux collections d'éléments: la collection d'entrée et la collection de sortie.

Ce n'est pas une erreur de relier les deux algorithmes: en fait, vous pouvez afficher les deux hiérarchiquement, où map est une spécialisation de foreach. Autrement dit, vous pouvez utiliser foreach et demander à l'opération de transformer son argument et de l'insérer dans une autre collection. Ainsi, l'algorithme foreach est une abstraction, une généralisation de l'algorithme map. En fait, étant donné que foreach ne comporte aucune restriction quant à son fonctionnement, nous pouvons dire en toute sécurité que foreach est le mécanisme de boucle le plus simple disponible et qu'il peut faire tout ce qu'une boucle peut faire. map, ainsi que d’autres algorithmes plus spécialisés, existe-t-il pour l’expression: si vous souhaitez mapper (ou transformer) une collection en une autre, votre intention est plus claire si vous utilisez map que si vous utilisez foreach.

Nous pouvons approfondir cette discussion en considérant l'algorithme copy: une boucle qui clone une collection. Cet algorithme est aussi une spécialisation de l'algorithme foreach. Vous pouvez définir une opération qui, à partir d'un élément, insérera ce même élément dans une autre collection. Si vous utilisez foreach avec cette opération, vous utiliserez effectivement l'algorithme copy, avec toutefois une clarté, une expressivité ou une explicité réduite. Allons encore plus loin: nous pouvons dire que map est une spécialisation de copy, elle-même une spécialisation de foreach. map may change n'importe lequel des éléments sur lesquels il est itéré. Si map ne change aucun élément, il ne fait que copier les éléments, et utiliser copier exprimerait plus clairement l'intention.

L'algorithme foreach peut lui-même ou non avoir une valeur de retour, en fonction de la langue. En C++, par exemple, foreach renvoie l'opération reçue à l'origine. L'idée est que l'opération peut avoir un état, et vous voudrez peut-être qu'elle revienne pour examiner son évolution au fil des éléments. map peut également ou non renvoyer une valeur. En C++, transform (l'équivalent de map ici) renvoie un itérateur à la fin du conteneur de sortie (collection). En Ruby, la valeur de retour de map est la séquence de sortie (collection). Ainsi, la valeur de retour des algorithmes est vraiment un détail d'implémentation; leur effet peut être ou ne pas être ce qu'ils retournent.

40
wilhelmtell

Array.protototype.map méthode & Array.protototype.forEach sont très similaires.

Exécutez le code suivant: 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));
});

Ils donnent le résultat idem exact.

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

Mais la torsion vient lorsque vous exécutez le code suivant: -

Ici, j'ai simplement assigné le résultat de la valeur de retour de la carte et des méthodes 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();

Maintenant, le résultat est quelque chose de délicat!

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

Conclusion

Array.prototype.map renvoie un tableau mais Array.prototype.forEach ne le fait pas. Vous pouvez donc manipuler le tableau renvoyé dans la fonction de rappel transmise à la méthode map, puis le renvoyer.

Array.prototype.forEach ne fait que parcourir le tableau donné afin que vous puissiez effectuer vos tâches tout en parcourant le tableau.

31
abhisekp

Réponse courte: map et forEach sont différents. De manière informelle, map est un sur-ensemble strict de forEach.

Réponse longue: Tout d'abord, décrivons une description en une ligne de forEach et map:

  • forEach itère sur tous les éléments, appelant la fonction fournie sur chacun d'eux.
  • map itère sur tous les éléments, en appelant la fonction fournie sur chacun d'eux, et produit un tableau transformé en se souvenant du résultat de chaque appel de fonction.

Dans de nombreuses langues, forEach est souvent appelé simplement each. La discussion suivante utilise JavaScript uniquement à titre de référence. Cela pourrait vraiment être n'importe quelle autre langue.

Maintenant, utilisons chacune de ces fonctions.

Utiliser forEach:

Tâche 1: Ecrivez une fonction printSquares, qui accepte un tableau de nombres arr et affiche le carré de chaque élément en elle.

Solution 1:

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

Utiliser map:

Tâche 2: Ecrivez une fonction selfDot, qui accepte un tableau de nombres arr et renvoie un tableau dans lequel chaque élément est le carré de l'élément correspondant dans arr.

De côté: ici, en termes d'argot, nous essayons de mettre en carré le tableau d'entrée. Formellement, nous essayons de calculer son produit scalaire avec lui-même.

Solution 2:

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

Comment map est-il un sur-ensemble de forEach?

Vous pouvez utiliser map pour résoudre les deux tâches, Tâche 1 et Tâche 2 . Cependant, vous ne pouvez pas utiliser forEach pour résoudre la tâche 2 .

Dans Solution 1 , si vous remplacez simplement forEach par map, la solution sera toujours valide. Dans Solution 2 , toutefois, remplacer map par forEach rompra votre solution qui fonctionnait auparavant.

Implémentation de forEach en termes de map:

Une autre façon de réaliser la supériorité de map consiste à implémenter forEach en termes de map. En tant que bons programmeurs, nous ne nous livrerons pas à la pollution des espaces de noms. Nous appellerons notre forEach, juste each.

Array.prototype.each = function (func) {
    this.map(func);
};

Maintenant, si vous n'aimez pas le non-sens prototype, voici:

var each = function (arr, func) {
    arr.map(func); // Or map(arr, func);
};

Alors, euh .. Pourquoi forEach existe-t-il même?

La réponse est l'efficacité. Si vous n'êtes pas intéressé par la transformation d'un tableau en un autre tableau, pourquoi devriez-vous calculer le tableau transformé? Seulement pour le vider? Bien sûr que non! Si vous ne voulez pas de transformation, vous ne devriez pas faire de transformation.

Ainsi, alors que map peut être utilisé pour résoudre la tâche 1 , il ne devrait probablement pas. Pour chacun est le bon candidat pour cela.


Réponse originale:

Bien que je sois largement d’accord avec la réponse de @madlep, je voudrais souligner que map() est un super-ensemble strict de forEach().

Oui, map() est généralement utilisé pour créer un nouveau tableau. Cependant, il peut également être utilisé pour changer le tableau actuel.

Voici un exemple:

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

Dans l'exemple ci-dessus, a a été défini de manière pratique, de sorte que a[i] === i Pour i < a.length. Même dans ce cas, il démontre le pouvoir de map().

Voici la description officielle de map() . Notez que map() peut même changer le tableau sur lequel il est appelé! Salut map().

J'espère que cela a aidé.


Édité le 10 novembre 2015: Ajout de l’élaboration.

11
Sumukh Barve

la différence la plus "visible" est que la carte accumule le résultat dans une nouvelle collection, tandis que foreach ne concerne que l'exécution elle-même.

mais il y a quelques hypothèses supplémentaires: puisque le "but" de map est la nouvelle liste de valeurs, l'ordre d'exécution n'est pas important. En fait, certains environnements d’exécution génèrent du code parallèle, voire introduisent des mémos pour éviter d’appeler des valeurs répétées, ou lazyness, pour éviter d’en appeler du tout.

foreach, en revanche, est appelé spécifiquement pour les effets secondaires; par conséquent, l'ordre est important et ne peut généralement pas être mis en parallèle.

11
Javier

Voici un exemple dans Scala en utilisant des listes: map renvoie liste, foreach ne renvoie rien.

def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit

Donc, map renvoie la liste résultant de l'application de la fonction f à chaque élément de la liste:

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 applique simplement f à chaque élément:

scala> var sum = 0
sum: Int = 0

scala> list foreach (sum += _)

scala> sum
res2: Int = 6 // res1 is empty
3
irudyak

Si vous parlez de Javascript en particulier, la différence est que map est une fonction de boucle alors que forEach est un itérateur.

Utilisez map lorsque vous souhaitez appliquer une opération à chaque membre de la liste et récupérer les résultats sous forme de nouvelle liste, sans affecter la liste d'origine.

Utilisez forEach lorsque vous voulez faire quelque chose à partir de chaque élément de la liste. Vous pourriez ajouter des éléments à la page, par exemple. Pour l’essentiel, c’est génial lorsque vous voulez des "effets secondaires".

Autres différences: forEach ne renvoie rien (puisqu'il s'agit en réalité d'une fonction de flux de contrôle), et la fonction transmise obtient des références à l'index et à la liste entière, tandis que map renvoie la nouvelle liste et ne transmet que la liste en cours. élément.

2
phyzome

ForEach essaie d'appliquer une fonction telle que l'écriture à db etc. sur chaque élément du RDD sans rien retourner en retour.

Mais la map() applique une fonction sur les éléments de rdd et renvoie le rdd. Ainsi, lorsque vous exécutez la méthode ci-dessous, elle n'échouera pas sur line3, mais lors de la collecte du fichier rdd après avoir demandé foreach, elle échouera et générera une erreur indiquant

Fichier "<stdin>", ligne 5, dans <module>

AttributeError: l'objet 'NoneType' n'a pas d'attribut '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())
0
user2456047