чем отличается каждый метод и метод collect в Ruby [duplicate]

этот вопрос уже есть ответ здесь:

из этого кода я не знаю разницы между двумя методами,collect и 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

7 ответов


Array#each принимает массив и применяет данный блок ко всем элементам. Он не влияет на массив и не создает новый объект. Это просто способ зацикливания на предметах. Также он возвращает себя.

  arr=[1,2,3,4]
  arr.each {|x| puts x*2}

печатает 2,4,6,8 и возвращает [1,2,3,4] независимо от того, что

Array#collect это то же самое, что Array#map и он применяет данный блок кода ко всем элементам и возвращает новый массив. проще говоря 'проецирует каждый элемент последовательности в новый форма'

  arr.collect {|x| x*2}

возвращает [2,4,6,8]

и в коде

 a = ["L","Z","J"].collect{|x| puts x.succ} #=> M AA K 

A-это массив, но на самом деле это массив нулей [Нил, Нил, Нил], потому что puts x.succ возвращает nil (хотя он печатает M AA K).

и

 b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K

также является массивом. Но его значение ["L","Z", "J"], потому что он возвращает себя.


Array#each просто берет каждый элемент и помещает его в блок, затем возвращает исходный массив. Array#collect берет каждый элемент и помещает его в новый массив, который возвращается:

[1, 2, 3].each { |x| x + 1 }    #=> [1, 2, 3]
[1, 2, 3].collect { |x| x + 1 } #=> [2, 3, 4]

each - Это когда вы хотите перебирать массив и делать все, что хотите, на каждой итерации. В большинстве (императивных) языков это молоток "один размер подходит всем", который программисты достигают, когда вам нужно обработать список.

для более функциональных языков вы делаете только такую общую итерацию, если не можете сделать это каким-либо другим способом. Большую часть времени, либо карта или уменьшить будет более подходящим (собирать и вводить в ruby)

collect - когда вы хотите превратить один массив в другой массив

inject - это когда вы хотите превратить массив в одно значение


вот два фрагмента исходного кода, согласно 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() возвращает значение, возвращаемое блоком (см. также это сообщение в блоге о метапрограммировании).

так each просто доходность и возвращает исходный массив, в то время как collect создает новый массив и помещает в него результаты блока; затем он возвращает этот новый массив.

источник фрагментов кода: каждого, собрать


разница в том, что он возвращает. В вашем примере выше a == [nil,nil,nil] (значение puts x.succ) пока b == ["L", "Z", "J"] (исходный массив)

из ruby-doc collect делает следующее:

вызывается один раз для каждого элемента личность. Создает новый массив, содержащий значения, возвращаемые блоком.

каждый всегда возвращает исходный массив. Смысл?


каждый метод определяется всеми классами, которые включают перечисляемый модуль. Object.eachвозвращает


Я думаю, что более простой способ понять это было бы, как показано ниже:

nums = [1, 1, 2, 3, 5]
square = nums.each { |num| num ** 2 } # => [1, 1, 2, 3, 5]

вместо этого, если вы используете collect:

square = nums.collect { |num| num ** 2 } # => [1, 1, 4, 9, 25]

и плюс, вы можете использовать .collect! для изменения исходного массива.