Array # each vs Array # map

92
hash = { "d" => [11, 22], "f" => [33, 44, 55] }

# case 1
hash.map {|k,vs| vs.map {|v| "#{k}:#{v}"}}.join(",")
=> "d:11,d:22,f:33,f:44,f:55"

# case 2
hash.map {|k,vs| vs.each {|v| "#{k}:#{v}"}}.join(",")
=> "11,22,33,44,55"

seule différence est le cas 1 utilise vs.map, le cas 2 utilise vs.each.

Que s'est-il passé ici?

user612308
la source

Réponses:

174

Array#each exécute le bloc donné pour chaque élément du tableau, puis renvoie le tableau lui-même.

Array#map exécute également le bloc donné pour chaque élément du tableau, mais retourne un nouveau tableau dont les valeurs sont les valeurs de retour de chaque itération du bloc.

Exemple: supposons que vous ayez un tableau défini ainsi:

arr = ["tokyo", "london", "rio"]

Ensuite, essayez d'exécuter each:

arr.each { |element| element.capitalize }
# => ["tokyo", "london", "rio"]

Notez que la valeur de retour est simplement le même tableau. Le code à l'intérieur du eachbloc est exécuté, mais les valeurs calculées ne sont pas renvoyées; et comme le code n'a pas d'effets secondaires, cet exemple n'effectue aucun travail utile.

En revanche, l'appel de la mapméthode du tableau retourne un nouveau tableau dont les éléments sont les valeurs de retour de chaque cycle d'exécution du mapbloc:

arr.map { |element| element.capitalize }
# => ["Tokyo", "London", "Rio"]
Olives
la source
Réponse parfaite pour comprendre. Juste un .. Clause de non-responsabilité: Si vous abusez de la valeur de retour de la fonction de carte, vous risquez de perdre beaucoup de mémoire.
Imran Ahmad le
33

Les effets secondaires sont les mêmes, ce qui ajoute une certaine confusion à votre rétro-ingénierie.

Oui, les deux itèrent sur le tableau (en fait, sur tout ce qui se mélange dans Enumerable ) mais la carte renverra un tableau composé des résultats du bloc tandis que chacun retournera simplement le tableau d'origine.

La valeur de retour de chacun est juste le tableau d'origine et est rarement utilisée dans le code Ruby, mais la carte est l'un des outils fonctionnels les plus importants .

Ce qui mapfait est de retourner un tableau qui contient les résultats du bloc ou de la méthode nommée qui est passé. Par exemple:

    2.2.3 :001 > [:how, :now, :brown, :cow].map &:to_s
 => ["how", "now", "brown", "cow"]

Dans ce cas, je n'ai pas passé un bloc mais juste un Symbol, cependant les class Symbolobjets ont une to_procméthode qui se traduira par:

[:how.to_s, :now.to_s, ...]

BTW, vous pouvez avoir du mal à trouver la documentation car map est une méthode dans Enumerable tandis que chacun (la méthode requise par le module Enumerable ) est une méthode dans Array .

Pour simplifier: l' implémentation de la carte est basée sur chacun .

DigitalRoss
la source
13

Voici une démonstration rapide de la différence entre la carte et chacune

a = ["a", "b", "c"];
#Array.map
p a.map {|item| "map_" + item}
#prints ["map_a", "map_b", "map_c"]

#Array.each
p a.each {|item| "map_" + item}
#prints ["a", "b", "c"]

Vous voyez que les rendements de carte ["map_a", "map_b", "map_c"]alors que chaque seulement itère mais renvoie le tableau d' origine: ["a", "b", "c"].

Ainsi, chacun est utilisé pour traiter un tableau et la carte est utilisée pour faire quelque chose avec un tableau traité.

Rima
la source
4

.each renvoie le même tableau que vous avez fourni initialement:

[1,2,3].each { |i| i + 1 }
#=> [1,2,3]

.map renvoie un nouveau tableau à partir des résultats de chaque appel de bloc:

[1,2,3].map { |i| i + 1 }
#=> [2,3,4]
Pastullo
la source
1

Array # chaque méthode renvoie le même tableau

a = [1,2,3,4,5]
a.object_id #70284994490700

b = a.each {|n| n + 2}
p b #[1,2,3,4,5]
b.object_id #70284994490700 <<--- it's the same as a

La méthode Array # map renvoie un nouveau tableau

c = [1,2,3,4,5]
c.object_id #70219117705860

d = c.map {|n| n + 2}
p d #[3,4,5,6,7]
d.object_id #70284994343620  <<---- it's different than c
user3007294
la source
0

lorsque vous utilisez map to a hash, il convertit implicitement le hash en un tableau, donc vous avez

[["d", [11, 22]], ["f", [33, 44, 55]]]

vs.each {...} ne vous renvoie que la dernière évaluation, qui est [11, 22] pour ["d", [11, 22]] et [33, 44, 55] pour ["f", [ 33, 44, 55]]. Donc avant la dernière jointure, vous avez

[[11, 22], [33, 44, 55]]
Sawa
la source
0

Vous pouvez également utiliser mapavec bang map!ce tableau source de changement

Aleksandr Babushkin
la source
Ce n'est pas une réponse à la question. la question porte sur la différence entre each, qui exécute le bloc donné et renvoie le tableau d'origine; et map, qui renvoie un tableau avec le résultat de l'exécution du bloc en tant que valeurs
Sampson Crowley