array - ruby slice
¿Diferencia entre mapa y coleccionar en ruby? (5)
¡Los collect
y collect!
¡Los métodos son alias para map
y map!
, por lo que pueden ser utilizados indistintamente. Aquí hay una manera fácil de confirmar que:
Array.instance_method(:map) == Array.instance_method(:collect)
=> true
He buscado en Google y tengo opiniones parciales / contradictorias: ¿existe realmente alguna diferencia entre hacer un map
y hacer una collect
en una matriz en Ruby / Rails?
Los docs no parecen sugerir nada, pero ¿existen diferencias en el método o el rendimiento?
Hice una prueba de referencia para intentar responder esta pregunta, luego encontré esta publicación, así que aquí están mis conclusiones (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 gratis?
No hay diferencia, de hecho, el map
se implementa en C como rb_ary_collect
y enum_collect
(por ejemplo, hay una diferencia entre el map
en una matriz y en cualquier otra enumeración, pero no hay diferencia entre el map
y la collect
).
¿Por qué tanto el map
como la collect
existen en Ruby? La función de map
tiene muchas convenciones de nombres en diferentes idiomas. Wikipedia proporciona una visión general :
La función de mapa se originó en lenguajes de programación funcionales, pero hoy en día se admite (o puede definirse) en muchos lenguajes de procedimiento, orientados a objetos y de paradigma múltiple: en la biblioteca de plantillas estándar de C ++, se denomina
transform
, en C # (3.0) '' En la biblioteca LINQ, se proporciona como un método de extensión llamadoSelect
. El mapa 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 los tres idiomas. También se proporciona un alias decollect
para el mapa en Ruby (de Smalltalk) [énfasis mío]. Common Lisp proporciona una familia de funciones tipo mapa; el que corresponde al comportamiento descrito aquí se llamamapcar
(-car indica el acceso mediante la operación CAR).
Ruby proporciona un alias para que los programadores del mundo de Smalltalk se sientan más cómodos.
¿Por qué hay una implementación diferente para arrays y enumeraciones? Una enumeración es una estructura de iteración generalizada, lo que significa que no hay forma en que Ruby pueda predecir lo que puede ser el siguiente elemento (puede definir enumeraciones infinitas, vea Prime para un ejemplo). Por lo tanto, debe llamar a una función para obtener cada elemento sucesivo (normalmente este será el método de each
).
Las matrices son la colección más común, por lo que es razonable optimizar su rendimiento. Dado que Ruby sabe mucho acerca de cómo funcionan los arreglos, no tiene que llamar a each
pero solo puede usar la manipulación simple de punteros, que es significativamente más rápida.
Existen optimizaciones similares para varios métodos de Array como zip
o count
.
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;
}
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 | bloque} → new_ary
- ary.map {| item | bloque} → new_ary
- ary.collect → an_enumerator
- ary.map → an_enumerator
Invoca el bloque una vez por cada elemento del yo. Crea una nueva matriz que contiene los valores devueltos por el bloque. Véase también Enumerable # collect.
Si no se da ningún bloque, se devuelve un enumerador.
a = [ "a", "b", "c", "d" ] a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a #=> ["a", "b", "c", "d"]