2011-03-10 20 views
349

He buscado en Google esto y obtuve opiniones contradictorias: ¿hay alguna diferencia entre hacer map y hacer collect en una matriz en Ruby/Rails?Diferencia entre el mapa y coleccionar en Ruby?

El docs no parece sugerir ninguno, pero ¿hay quizás diferencias en el método o el rendimiento?

+3

'map' se prefiere en [Código de Golf] (http://codegolf.stackexchange.com/questions). –

+1

Como una explicación de por qué 'map' se prefiere en CodeGolf, lo que podría no ser obvio para todos: es solo porque' collect' es cuatro caracteres más largos que 'map', pero lo mismo en funcionalidad. –

Respuesta

401

No hay diferencia, de hecho map se implementa en C como rb_ary_collect y enum_collect (por ejemplo., Hay una diferencia entre map en una matriz y en cualquier otro enum, pero no hay diferencia entre map y collect) .


¿Por qué tanto map y collect existen en Ruby? La función map tiene muchas convenciones de nombres en diferentes idiomas. Wikipedia provides an overview:

La función de mapa se originó en los lenguajes de programación funcionales, pero es apoyado hoy (o se puede definir) en muchos lenguajes de procedimientos, orientación a objetos, y multi-paradigma, así: En la Biblioteca de plantillas estándar C++ 's, se le llama transform, en la biblioteca LINQ de C# (3.0), se proporciona como un método de extensión llamado Select. Map es también una operación utilizada frecuentemente en lenguajes de alto nivel como Perl, Python y Ruby; la operación se llama map en los tres idiomas. Un alias collect para el mapa también se proporciona en Ruby (de Smalltalk) [énfasis mío]. Common Lisp proporciona una familia de funciones tipo mapa; el que corresponde al comportamiento descrito aquí se llama mapcar (-car que indica el acceso usando la operación CAR).

Ruby proporciona un alias para que los programadores del mundo Smalltalk se sientan como en casa.


Por qué hay una aplicación diferente para las matrices y las enumeraciones? Una enumeración es una estructura de iteración generalizada, lo que significa que no hay forma en que Ruby puede predecir cuál será el siguiente elemento puede ser (se puede definir enumeraciones infinitas, ver Prime para un ejemplo). Por lo tanto, debe llamar a una función para obtener cada elemento sucesivo (por lo general, este será el método each).

Las matrices son la colección más común, por lo que es razonable optimizar su rendimiento. Como Ruby sabe mucho sobre cómo funcionan las matrices, no tiene que llamar al each, pero solo puede usar el pointer manipulation, que es significativamente más rápido.

Existen optimizaciones similares para una serie de métodos de matriz como zip o count.

+8

@Mark Reed pero luego, los programadores que no vengan de SmallTalk estarían confundidos por tener dos funciones diferentes que resultan ser solo alias. Causa preguntas como la de OP arriba. – SasQ

+7

@SasQ No estoy en desacuerdo, creo que sería mejor en general si solo hubiera un nombre. Pero hay muchos otros alias en Ruby, y una característica del alias es que hay un buen nomenclatura paralela entre las operaciones * collect *, * detectar *, * inject *, * reject * y * select * (también conocido como * map *, * find *, * reduce *, * reject * (sin alias) y * find_all *). –

+2

De hecho. Aparentemente, Ruby está usando alias/sinónimos en más ocasiones. Por ejemplo, la cantidad de elementos en una matriz se puede recuperar con 'count',' length', o 'size'. Diferentes palabras para el mismo atributo de una matriz, pero con esto, Ruby le permite elegir la palabra más adecuada para su código: ¿desea el _número_ de elementos que está recopilando, la _ longitud_ de una matriz o el _ tamaño actual de la estructura. Básicamente, son todos iguales, pero elegir la palabra correcta puede hacer que su código sea más fácil de leer, lo cual es una buena propiedad del lenguaje. –

41

Me han dicho son lo mismo.

realidad que se documentan en el mismo lugar bajo ruby-doc.org:

http://www.ruby-doc.org/core/classes/Array.html#M000249

  • ary.collect {| artículo | bloque} → new_ary
  • ary.map {| item | block} → new_ary
  • ary.collect → an_enumerator
  • ary.map → an_enumerator

bloque Invoca una vez por cada elemento de auto. Crea una nueva matriz que contiene los valores devueltos por el bloque. Véase también Enumerable # collect.
Si no se proporciona 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"] 
+1

Sólo para ser exhaustiva: [http://www.ruby-doc.org/core/classes/Enumerable.html#method-i-map](http://www.ruby-doc.org/core/classes/ Enumerable.html # method-i-map) –

6

Ruby alias el método Array # map to Array # collect; se pueden usar indistintamente (Rubí 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; 
} 

http://ruby-doc.org/core-2.2.0/Array.html#method-i-map

+0

Deseo que la documentación indique explícitamente que son alias. Por el momento simplemente se referencian entre sí, y ambos tienen descripciones ligeramente diferentes. –

5

Hice una prueba de referencia para tratar de responder a esta pregunta, entonces encontrado este post así que aquí están mis conclusiones (que difieren ligeramente de las otras respuestas)

Este es 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?

Cuestiones relacionadas