collect
このコードから、2つの方法の違いはわかりません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]の配列です。これは、 (M AA Kを出力する場合でも)がputs x.succ
返されるためです。nil
と
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
配列を反復処理し、各反復で必要なことを実行する場合に使用します。ほとんどの(命令型)言語では、これは、リストを処理する必要があるときにプログラマーが到達する「1つのサイズですべてに対応する」ハンマーです。
より機能的な言語の場合、他の方法で実行できない場合にのみ、この種の一般的な反復を実行します。ほとんどの場合、マップまたはリデュースのいずれかがより適切です(ルビーで収集して注入します)
collect
ある配列を別の配列に変換したい場合に使用します
inject
配列を単一の値に変換したい場合に使用します
ドキュメントによると、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
だけで、新しい配列を作成してブロックの結果をその配列にプッシュします。次に、この新しい配列を返します。collect
違いはそれが返すものです。上記の例
a == [nil,nil,nil]
では、(puts x.succの値)while b == ["L", "Z", "J"]
(元の配列)
ruby-docから、collectは次のことを行います。
自己の要素ごとに1回ブロックを呼び出します。ブロックによって返される値を含む新しい配列を作成します。
それぞれが常に元の配列を返します。意味がありますか?
それぞれは、Enumerableモジュールを含むすべてのクラスによって定義されたメソッドです。オブジェクトObject.each
を返します。Enumerable::Enumerator
これは、他のEnumerableメソッドがオブジェクトを反復処理するために使用するものです。each
各クラスのメソッドの動作は異なります。
Arrayクラスでは、ブロックがに渡されるとeach
、各要素に対してブロックのステートメントが実行されますが、最終的にはselfが返されます。これは、配列が必要ないが、配列から要素を選択したい場合に便利です。他のメソッドへの引数としてasを使用します。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!
さらに、元の配列を変更するために使用できます。