web-dev-qa-db-ja.com

Rubyの各メソッドとcollectメソッドの違い

このコードから、2つのメソッドcollecteachの違いがわかりません。

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
61
mko

Array#eachは配列を受け取り、指定されたブロックをすべてのアイテムに適用します。配列には影響せず、新しいオブジェクトを作成します。これは単にアイテムをループする方法です。また、自己を返します。

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

2,4,6,8を出力し、[1,2,3,4]を返します

Array#collectArray#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.succnilを返すからです(たとえM AA Kを出力しても)。

そして

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

また、配列です。しかし、自己を返すため、その値は["L"、 "Z"、 "J"]です。

106
RameshVel

Array#eachは、各要素を取得してブロックに挿入し、元の配列を返します。 Array#collectは各要素を取り、それを新しい配列に入れて返します:

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

eachは、配列を繰り返し処理し、各繰り返しで必要な処理を実行する場合に使用します。ほとんどの(必須の)言語では、これは、リストを処理する必要があるときにプログラマが到達する「1つのサイズですべてに対応する」ハンマーです。

より機能的な言語の場合、他の方法で実行できない場合にのみ、この種の汎用反復を実行します。ほとんどの場合、mapまたはreduceのいずれかがより適切です(Rubyで収集および注入)

collectは、ある配列を別の配列に変換する場合に使用します

injectは、配列を単一の値に変換する場合に使用します

5
Matt Briggs

docs ...によると、2つのソースコードスニペットがあります。

_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 justyieldsと元の配列を返しますが、collectは新しい配列を作成し、その結果をプッシュしますそれにブロックします。次に、この新しい配列を返します。

ソーススニペット: eachcollect

2
miku

違いはそれが返すものです。上記の例ではa == [nil,nil,nil](puts x.succの値)b == ["L", "Z", "J"](元の配列)

Ruby-docから、collectは次のことを行います。

Selfの各要素に対してブロックを1回呼び出します。ブロックによって返された値を含む新しい配列を作成します。

それぞれが常に元の配列を返します。理にかなっていますか?

1
hb922

私はそれを理解する簡単な方法は次のようになると思います:

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!は元の配列を変更します。

0
Edmund Lee

それぞれは、Enumerableモジュールを含むすべてのクラスによって定義されるメソッドです。 Object.eachEnumerable::Enumeratorオブジェクトを返します。これは、オブジェクトを反復処理するために他のEnumerableメソッドが使用するものです。各クラスのeachメソッドの動作は異なります。

Arrayクラスでは、ブロックがeachに渡されると、各要素でブロックのステートメントを実行しますが、最終的にはselfを返します。これは、配列が不要な場合に便利ですが、配列から要素を選択し、他のメソッドへの引数として使用します。 inspectおよびmapは、各要素でのブロックの実行の戻り値を含む新しい配列を返します。 map!およびcollect!を使用して、元の配列で操作を実行できます。

0
serengeti12