2011-03-10 3 views
72
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, 2 cas utilise vs.each.Tableau # chaque vs carte tableau #

Que s'est-il passé ici?

Répondre

137

Array#each exécute le bloc donné pour chaque élément du tableau, puis retourne 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 avez un tableau défini ainsi:

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

Ensuite, essayez d'exécuter each:

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

Notez la valeur de retour est tout simplement le même tableau. Le code à l'intérieur du bloc each 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, appeler la méthode de tableau map retourne un nouveau tableau dont les éléments sont les valeurs de retour de chaque tour de l'exécution du bloc map:

arr.map { |element| element.capitalize } 
# => ["Tokyo", "London", "Rio"] 
+0

de réponse parfaite à comprendre. Juste un .. Clause de non-responsabilité: Si vous utilisez trop la valeur de retour de la fonction de carte, vous risquez de perdre beaucoup de mémoire. – Imran

0

lorsque vous utilisez la carte à un hachage, il jette implicitement le hachage à un tableau, vous avez donc

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

vs.each {...} ne vous donne de nouveau la dernière évaluation, qui est [ 11, 22] pour ["d", [11, 22]] et [33, 44, 55] pour ["f", [33, 44, 55]]. Alors avant de rejoindre la dernière, vous avez

[[11, 22], [33, 44, 55]] 
28

Les side effects sont les mêmes qui ajoute une certaine confusion à votre ingénierie inverse.

Oui, les deux itérer sur le tableau (en fait, sur tout ce qui se mélange à Enumerable) mais map retourne un tableau composé des résultats de bloc alors que each va simplement retourner le tableau original.

La valeur de retour de each est juste le tableau d'origine et est rarement utilisée dans le code Ruby mais map est l'un des most important functional tools.

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

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

Dans ce cas, je ne suis pas passé un bloc, mais juste un Symbol, mais class Symbol objets ont une méthode to_proc qui se traduira par:

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

BTW, vous pouvez avoir difficile de trouver la documentation car carte est une méthode dans Enumerable tandis que chaque (la seule méthode requise par le Enumerable module) est une méthode dans Array.

Comme une note de trivia: l'implémentation carte est basée sur chaque.

2

.each renvoie le même tableau que vous avez fourni au départ:

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

.map retourne un nouveau tableau sur les résultats de chaque appel de bloc:

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

Voici une démonstration rapide de la façon dont la carte est différente de chaque

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 cette carte renvoie ["map_a", "map_b", "map_c"] alors que chaque itère juste mais retourne le tableau original: ["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é.

0

Tableau # chaque méthode retourne 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 

méthode Array # map retourne 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