objetos - lo que es diferente entre cada método y recoger en Ruby
manejo de objetos en ruby (7)
Esta pregunta ya tiene una respuesta aquí:
- Array # each vs. Array # map 6 respuestas
De este código no sé la diferencia entre los dos métodos, collect
y each
.
a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K
print a.class #=> Array
b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K
print b.class #=> Array
Aquí están los dos fragmentos de código fuente, de acuerdo con los docs ...
VALUE
rb_ary_each(VALUE ary)
{
long i;
RETURN_ENUMERATOR(ary, 0, 0);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_PTR(ary)[i]);
}
return ary;
}
# .... .... .... .... .... .... .... .... .... .... .... ....
static VALUE
rb_ary_collect(VALUE ary)
{
long i;
VALUE collect;
RETURN_ENUMERATOR(ary, 0, 0);
collect = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i]));
}
return collect;
}
rb_yield()
devuelve el valor devuelto por el bloque ( consulte también esta publicación de blog en metaprogramación ).
Así que each
solo cede y devuelve la matriz original, mientras que la collect
crea una nueva matriz y empuja los resultados del bloque hacia ella; luego devuelve esta nueva matriz.
Cada uno es un método definido por todas las clases que incluyen el módulo Enumerable. Object.each
devuelve un objeto Enumerable::Enumerator
. Esto es lo que otros métodos Enumerable usan para iterar a través del objeto. each
método de cada clase se comporta de manera diferente.
En la clase Array, cuando se pasa un bloque a each
, realiza declaraciones del bloque en cada elemento, pero al final se devuelve self. Esto es útil cuando no se necesita una matriz, pero tal vez solo se desee elegir elementos del bloque. matriz y utilizar los argumentos como a otros métodos. inspect
y map
devuelve una nueva matriz con valores de retorno de la ejecución del bloque en cada elemento. Puedes usar el map!
y collect!
para realizar operaciones en la matriz original.
Creo que una forma más fácil de entenderlo sería la siguiente:
nums = [1, 1, 2, 3, 5]
square = nums.each { |num| num ** 2 } # => [1, 1, 2, 3, 5]
En cambio, si usas collect:
square = nums.collect { |num| num ** 2 } # => [1, 1, 4, 9, 25]
Y además, puedes usar .collect!
para mutar la matriz original.
La diferencia es lo que devuelve. En su ejemplo anterior a == [nil,nil,nil]
(el valor de puts x.succ) while b == ["L", "Z", "J"]
(la matriz original)
Del ruby-doc, collect hace lo siguiente:
Invoca bloque una vez para cada elemento de uno mismo. Crea una nueva matriz que contiene los valores devueltos por el bloque.
Cada uno siempre devuelve el conjunto original. ¿Tiene sentido?
Array#each
simplemente toma cada elemento y lo coloca en el bloque, luego devuelve el conjunto original. Array#collect
toma cada elemento y lo coloca en una nueva matriz que se devuelve:
[1, 2, 3].each { |x| x + 1 } #=> [1, 2, 3]
[1, 2, 3].collect { |x| x + 1 } #=> [2, 3, 4]
Array#each
toma una matriz y aplica el bloque dado sobre todos los elementos. No afecta la matriz o crea un nuevo objeto. Es solo una forma de pasar por encima de los elementos. También regresa a sí mismo.
arr=[1,2,3,4]
arr.each {|x| puts x*2}
Imprime 2,4,6,8 y devuelve [1,2,3,4] pase lo que pase
Array#collect
es igual que Array#map
y aplica el bloque de código dado en todos los elementos y devuelve la nueva matriz. simplemente ponga ''Proyecta cada elemento de una secuencia en una nueva forma''
arr.collect {|x| x*2}
Devuelve [2,4,6,8]
Y en tu código
a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K
a es una matriz pero en realidad es una matriz de Nil [nil, nil, nil] porque puts x.succ
devuelve nil
(aunque imprima M AA K).
Y
b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K
también es una matriz. Pero su valor es ["L", "Z", "J"], porque regresa a sí mismo.
each
es para cuando quieras iterar sobre una matriz y hacer lo que quieras en cada iteración. En la mayoría de los idiomas (imperativos), este es el martillo de "talla única" al que los programadores recurren cuando necesita procesar una lista.
Para lenguajes más funcionales, solo realiza este tipo de iteración genérica si no puede hacerlo de otra manera. La mayoría de las veces, ya sea mapa o reducir será más apropiado (recoger e inyectar en rubí)
collect
es para cuando quieres convertir una matriz en otra matriz
inject
es para cuando quieres convertir una matriz en un solo valor