Diferencia entre mapa y recoger en Ruby?
He buscado esto en Google y tengo opiniones irregulares / contradictorias - ¿hay realmente alguna diferencia entre hacer un map
y hacer un collect
en una matriz en Ruby/Rails?
Los documentos no parecen sugerir ninguno, pero ¿hay quizás diferencias en el método o el rendimiento?
5 answers
No hay diferencia, de hecho map
se implementa en C como rb_ary_collect
y enum_collect
(eg. hay una diferencia entre map
en una matriz y en cualquier otra enumeración, pero no hay diferencia entre map
y collect
).
¿Por qué existen tanto map
como collect
en Ruby? La función map
tiene muchas convenciones de nombres en diferentes idiomas. Wikipedia proporciona una visión general :
La función map se originó en lenguajes de programación funcionales, pero es hoy soportado (o puede ser definido) en muchos lenguajes procedimentales, orientados a objetos y multi-paradigma: En la Biblioteca de Plantillas Estándar de C++, se llama
transform
, en la biblioteca LINQ de C# (3.0), se proporciona como un método de extensión llamadoSelect
. Map también es una operación de uso frecuente en lenguajes de alto nivel como Perl, Python y Ruby; la operación se llamamap
en estos tres lenguajes. Uncollect
alias para map también se proporciona en Ruby (de Smalltalk) [énfasis mío]. Common Lisp proporciona una familia de funciones similares a un mapa; la que corresponde al comportamiento descrito aquí se llamamapcar
(-car que indica el acceso mediante la operación CAR).
Ruby proporciona un alias para que los programadores del mundo de Smalltalk se sientan más como en casa.
¿Por qué hay una implementación diferente para arrays y enums? Una enumeración es una estructura de iteración generalizada, lo que significa que no hay manera de que Ruby pueda predecir cuál es el siguiente elemento puede ser (puede definir enumeraciones infinitas, ver Prime para un ejemplo). Por lo tanto, debe llamar a una función para obtener cada elemento sucesivo (típicamente este será el método each
).
Los arrays son la colección más común, por lo que es razonable optimizar su rendimiento. Dado que Ruby sabe mucho sobre cómo funcionan los arrays, no tiene que llamar a each
, sino que solo puede usar una simple manipulación del puntero que es significativamente más rápida.
Optimizaciones similares existen para un número de métodos de matriz como zip
o count
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-30 12:33:02
Me han dicho que son lo mismo.
En realidad están documentados en el mismo lugar bajo 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.recoger → an_enumerador
- ary.mapa → an_enumerador
Invoca block una vez para cada elemento de self. Crea una nueva matriz contiene los valores devueltos por el bloque. Véase también Enumerable # collect.
Si no se da ningún bloque, se devuelve un enumerador en su lugar.a = [ "a", "b", "c", "d" ] a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a #=> ["a", "b", "c", "d"]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-10 17:00:02
Hice una prueba de referencia para tratar de responder a esta pregunta, luego encontré este post, así que aquí están mis hallazgos (que difieren ligeramente de las otras respuestas)
Aquí está el código de referencia:
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
Y los resultados que obtuve fueron:
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)
Tal vez un alias no es libre?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-01 00:52:28
Ruby alias el método Array#map to Array#collect; se pueden usar indistintamente. (Ruby Monk)
En otras palabras, el mismo código fuente :
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-27 02:25:02
Los métodos collect
y collect!
son alias de map
y map!
, por lo que se pueden usar indistintamente. Aquí hay una manera fácil de confirmar que:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-01 20:05:57