Из этого кода я не знаю разницы между двумя методами, 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
Из этого кода я не знаю разницы между двумя методами, 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
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 - массив, но на самом деле это массив из Nil [nil, nil, nil], потому что puts x.succ
возвращает nil
(даже если он печатает M AA K).
И
b = ["L","Z","J"].each{|x| puts x.succ} #=> M AA K
также является массивом. Но его значение равно [ "L", "Z", "J" ], поскольку оно возвращает self.
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
- это то, когда вы хотите перебирать массив и делать все, что хотите на каждой итерации. На большинстве (императивных) языках это "один размер подходит всем" молоткам, к которым стремятся программисты, когда вам нужно обработать список.
Для более функциональных языков вы делаете только такую родовую итерацию, если не можете сделать это иначе. В большинстве случаев, карта или сокращение будут более подходящими (собирать и вводить в рубине).
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 собирает следующее:
Вызывает блок один раз для каждого элемента самостоятельно. Создает новый массив, содержащий значения, возвращаемые блоком.
Каждый всегда возвращает исходный массив. Имеет смысл?
Каждый из них - это метод, определяемый всеми классами, которые включают в себя модуль Enumerable. Object.each
возвращает объект Enumerable::Enumerator
. Это то, что другие методы Enumerable используют для итерации через объект. each
методы каждого класса ведут себя по-разному.
В классе Array, когда блок передается в each
, он выполняет инструкции блока для каждого элемента, но в конце возвращает self.This полезен, когда вам не нужен массив, но вы, возможно, просто хотите для выбора элементов из массива и использования аргументов в качестве других методов. inspect
и map
возвращает новый массив с возвращаемыми значениями выполнения блока для каждого элемента. Вы можете использовать map!
и collect!
для выполнения операций с исходным массивом.
Я думаю, что более простой способ понять это будет следующим:
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!
для изменения исходного массива.