what's different between each and collect method in Ruby [duplicate]
Asked Answered
E

7

69

From this code I don't know the difference between the two methods, collect and 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
Excommunicative answered 18/3, 2011 at 4:6 Comment(2)
Why are you printing a.class, b.class? Print a and b instead, and it will be clear. See Refactor's answer. I think you are confusing the effect of your two one-liners, which are the same, and the return value of them, which are different.Foraminifer
Use p instead of print when you want to see the content of an object. I forgot to mention that. Try p a and p b in you code above.Foraminifer
L
118

Array#each takes an array and applies the given block over all items. It doesn't affect the array or creates a new object. It is just a way of looping over items. Also it returns self.

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

Prints 2,4,6,8 and returns [1,2,3,4] no matter what

Array#collect is same as Array#map and it applies the given block of code on all the items and returns the new array. simply put 'Projects each element of a sequence into a new form'

  arr.collect {|x| x*2}

Returns [2,4,6,8]

And In your code

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

a is an Array but it is actually an array of Nil's [nil,nil,nil] because puts x.succ returns nil (even though it prints M AA K).

And

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

also is an Array. But its value is ["L","Z","J"], because it returns self.

Lockwood answered 18/3, 2011 at 4:57 Comment(0)
M
41

Array#each just takes each element and puts it into the block, then returns the original array. Array#collect takes each element and puts it into a new array that gets returned:

[1, 2, 3].each { |x| x + 1 }    #=> [1, 2, 3]
[1, 2, 3].collect { |x| x + 1 } #=> [2, 3, 4]
Mobilize answered 18/3, 2011 at 4:10 Comment(0)
G
6

each is for when you want to iterate over an array, and do whatever you want in each iteration. In most (imperative) languages, this is the "one size fits all" hammer that programmers reach for when you need to process a list.

For more functional languages, you only do this sort of generic iteration if you can't do it any other way. Most of the time, either map or reduce will be more appropriate (collect and inject in ruby)

collect is for when you want to turn one array into another array

inject is for when you want to turn an array into a single value

Grisons answered 18/3, 2011 at 4:27 Comment(0)
M
2

Here are the two source code snippets, according to the 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() returns the value returned by the block (see also this blog post on metaprogramming).

So each just yields and returns the original array, while collect creates a new array and pushes the results of the block into it; then it returns this new array.

Source snippets: each, collect

Modulus answered 18/3, 2011 at 4:18 Comment(0)
G
1

The difference is what it returns. In your example above a == [nil,nil,nil] (the value of puts x.succ) while b == ["L", "Z", "J"] (the original array)

From the ruby-doc, collect does the following:

Invokes block once for each element of self. Creates a new array containing the values returned by the block.

Each always returns the original array. Makes sense?

Geezer answered 18/3, 2011 at 4:14 Comment(0)
S
0

Each is a method defined by all classes that include the Enumerable module. Object.eachreturns a Enumerable::Enumerator Object. This is what other Enumerable methods use to iterate through the object. each methods of each class behaves differently.

In Array class when a block is passed to each, it performs statements of the block on each element, but in the end returns self.This is useful when you don't need an array, but you maybe just want to choose elements from the array and use the as arguments to other methods. inspect and map return a new array with return values of execution of the block on each element. You can use map! and collect! to perform operations on the original array.

Shameful answered 1/11, 2011 at 10:17 Comment(0)
I
0

I think an easier way to understand it would be as below:

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

Instead, if you use collect:

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

And plus, you can use .collect! to mutate the original array.

Inadequate answered 21/10, 2014 at 6:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.