J'ai recherché cela dans Google et obtenu des opinions contradictoires/contradictoires. Existe-t-il une différence entre faire un map
et faire un collect
sur un tableau dans Ruby/Rails?
Les docs ne semblent pas en suggérer, mais existe-t-il peut-être des différences de méthode ou de performance?
Il n'y a pas de différence, en fait, map
est implémenté dans C comme rb_ary_collect
et enum_collect
(par exemple, il y a une différence entre map
sur un tableau et sur toute autre énumération, mais aucune différence entre map
et collect
).
Pourquoi map
et collect
existent-ils en Ruby? La fonction map
comporte de nombreuses conventions de dénomination dans différentes langues. . Wikipedia en donne un aperç :
La fonction map a pour origine des langages de programmation fonctionnels, mais est aujourd'hui prise en charge (ou peut être définie) dans de nombreux langages procéduraux, orientés objet et à paradigmes multiples: dans la bibliothèque de modèles standard de C++, elle s'appelle
transform
, en C #. Bibliothèque LINQ (3.0), elle est fournie sous forme de méthode d’extension appeléeSelect
. Map est également une opération fréquemment utilisée dans les langages de haut niveau tels que Perl, Python et Ruby; l'opération s'appellemap
dans les trois langues. Un aliascollect
pour map est également fourni dans Ruby (à partir de Smalltalk) [l'emphase mienne]. Common LISP fournit une famille de fonctions semblables à des cartes; celui qui correspond au comportement décrit ici s'appellemapcar
(-car indiquant l'accès à l'aide de l'opération CAR).
Ruby fournit un alias aux programmeurs du monde Smalltalk pour qu'ils se sentent plus à l'aise.
Pourquoi existe-t-il une implémentation différente pour les tableaux et les énumérations? Une énumération est une structure d'itération généralisée, ce qui signifie qu'il n'y a aucun moyen dans lequel Ruby peut prédire ce que le prochain élément peut être (vous pouvez définir un enum infini, voir Prime pour un exemple). Par conséquent, il doit appeler une fonction pour obtenir chaque élément successif (ce sera généralement la méthode each
).
Les tableaux étant la collection la plus courante, il est raisonnable d'optimiser leurs performances. Puisque Ruby en sait beaucoup sur le fonctionnement des tableaux, il n'est pas nécessaire d'appeler each
, mais vous ne pouvez utiliser que la simple manipulation du pointeur , ce qui est nettement plus rapide.
Des optimisations similaires existent pour un certain nombre de méthodes Array telles que Zip
ou count
.
On m'a dit ce sont les mêmes.
En fait, ils sont documentés au même endroit sous Ruby-doc.org:
http://www.Ruby-doc.org/core/classes/Array.html#M000249
- ary.collect {| item | block} → new_ary
- ary.map {| item | block} → new_ary
- ary.collect → un_numérateur
- ary.map → un_numérateur
Invoque le bloc une fois pour chaque élément de soi. Crée un nouveau tableau contenant les valeurs renvoyées par le bloc. Voir aussi Enumerable # collect.
Si aucun bloc n'est donné, un énumérateur est retourné à la place.a = [ "a", "b", "c", "d" ] a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a #=> ["a", "b", "c", "d"]
J'ai fait un test de référence pour essayer de répondre à cette question, puis j'ai trouvé ce billet alors voici mes conclusions (qui diffèrent légèrement des autres réponses)
Voici le code de référence:
require 'benchmark'
h = { abc: 'hello', 'another_key' => 123, 4567 => 'third' }
a = 1..10
many = 500_000
Benchmark.bm do |b|
GC.start
b.report("hash keys collect") do
many.times do
h.keys.collect(&:to_s)
end
end
GC.start
b.report("hash keys map") do
many.times do
h.keys.map(&:to_s)
end
end
GC.start
b.report("array collect") do
many.times do
a.collect(&:to_s)
end
end
GC.start
b.report("array map") do
many.times do
a.map(&:to_s)
end
end
end
Et les résultats que j'ai obtenus ont été:
user system total real
hash keys collect 0.540000 0.000000 0.540000 ( 0.570994)
hash keys map 0.500000 0.010000 0.510000 ( 0.517126)
array collect 1.670000 0.020000 1.690000 ( 1.731233)
array map 1.680000 0.020000 1.700000 ( 1.744398)
Peut-être qu'un alias n'est pas gratuit?
Ruby appelle la méthode Array # map to Array # collect; ils peuvent être utilisés de façon interchangeable. (Ruby Monk)
En d'autres termes, même code source:
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_Push(collect, rb_yield(RARRAY_AREF(ary, i)));
}
return collect;
}
Les méthodes collect
et collect!
sont des alias pour map
et map!
, de sorte qu'elles peuvent être utilisées de manière interchangeable. Voici un moyen simple de confirmer que:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true