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?

Author: Hauleth, 2011-03-10

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 llamado Select. Map también es una operación de uso frecuente en lenguajes de alto nivel como Perl, Python y Ruby; la operación se llama map en estos tres lenguajes. Un collect 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 llama mapcar (-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.

 431
Author: Jakub Hampl,
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"]
 46
Author: OscarRyz,
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?

 9
Author: ktec,
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;
}

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

 7
Author: jeton,
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
 0
Author: BrunoFacca,
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