De ce code, je ne connais pas la différence entre les deux méthodes, collect
et 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
Array#each
prend un tableau et applique le bloc donné à tous les éléments. Cela n'affecte pas le tableau ou crée un nouvel objet. C'est juste une façon de faire une boucle sur les objets. En outre, cela revient à soi.
arr=[1,2,3,4]
arr.each {|x| puts x*2}
Imprime 2,4,6,8 et retourne [1,2,3,4] quoi qu'il arrive
Array#collect
est identique à Array#map
et applique le bloc de code donné à tous les éléments et renvoie le nouveau tableau. Il suffit de mettre 'Projette chaque élément d’une séquence dans une nouvelle forme'
arr.collect {|x| x*2}
Retours [2,4,6,8]
Et dans votre code
a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K
a est un tableau mais il s’agit en fait d’un tableau de Nil \ [nil, nil, nil] car puts x.succ
renvoie nil
(même s’il affiche M AA K).
Et
b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K
est également un tableau. Mais sa valeur est ["L", "Z", "J"], car il revient à soi.
Array#each
prend juste chaque élément et le met dans le bloc, puis retourne le tableau d'origine. Array#collect
prend chaque élément et le place dans un nouveau tableau qui est renvoyé:
[1, 2, 3].each { |x| x + 1 } #=> [1, 2, 3]
[1, 2, 3].collect { |x| x + 1 } #=> [2, 3, 4]
each
est pour quand vous voulez itérer sur un tableau et faire ce que vous voulez dans chaque itération. Dans la plupart des langages (impératifs), il s'agit du marteau «taille unique» que les programmeurs recherchent lorsque vous devez traiter une liste.
Pour les langages plus fonctionnels, vous ne faites ce type d'itération générique que si vous ne pouvez le faire autrement. La plupart du temps, la carte ou la réduction sera plus appropriée (collecter et injecter en Ruby)
collect
est pour quand vous voulez transformer un tableau en un autre tableau
inject
est pour quand vous voulez transformer un tableau en une valeur unique
Voici les deux extraits de code source, selon le 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()
renvoie la valeur renvoyée par le bloc ( voir aussi cet article de blog sur la métaprogrammation ).
Donc each
ne fait que rendements et renvoie le tableau d'origine, alors que collect
crée un nouveau tableau et y insère les résultats du bloc; alors il retourne ce nouveau tableau.
La différence est ce qu'il revient. Dans votre exemple ci-dessus a == [nil,nil,nil]
(la valeur de met x.succ) tandis que b == ["L", "Z", "J"]
(le tableau d'origine)
À partir de Ruby-doc, collect effectue les opérations suivantes:
Invoque le bloc une fois pour chaque élément de soi. Crée un nouveau tableau contenant les valeurs renvoyées par le bloc.
Chacun retourne toujours le tableau d'origine. Logique?
Je pense qu'un moyen plus facile de comprendre ce serait comme ci-dessous:
nums = [1, 1, 2, 3, 5]
square = nums.each { |num| num ** 2 } # => [1, 1, 2, 3, 5]
Au lieu de cela, si vous utilisez collect:
square = nums.collect { |num| num ** 2 } # => [1, 1, 4, 9, 25]
De plus, vous pouvez utiliser .collect!
pour muter le tableau d'origine.
Chacune est une méthode définie par toutes les classes incluant le module Enumerable. Object.each
retourne un objet Enumerable::Enumerator
. C'est ce que d'autres méthodes Enumerable utilisent pour parcourir l'objet. Les méthodes each
de chaque classe se comportent différemment.
Dans la classe Array, lorsqu'un bloc est passé à each
, il exécute des instructions du bloc sur chaque élément, mais renvoie finalement self. Ceci est utile lorsque vous n'avez pas besoin d'un tableau, mais vous souhaitez peut-être simplement tableau et utiliser le comme arguments à d’autres méthodes. inspect
et map
retournent un nouveau tableau avec les valeurs renvoyées d'exécution du bloc sur chaque élément. Vous pouvez utiliser map!
et collect!
pour effectuer des opérations sur le tableau d'origine.