3

Ruby の列挙子を理解するのに苦労しています。

訂正してください私が間違っている場合、o.enum_for(:arg)メソッドはオブジェクトを列挙子に変換し、オブジェクトを反復するたびにメソッドoを呼び出す必要がありますargか? 私を混乱させるのは、このコード行がどのように機能するかです

[4, 1, 2, 0].enum_for(:count).each_with_index do |elem, index|
  elem == index
end

配列内の位置と等しい要素の数をカウントする必要があり、機能します。しかし、私は実際に何が起こっているのか理解していません。each_with_index反復ごとに count メソッドを呼び出していますか? 誰かが説明できれば、それは素晴らしいことです。

4

2 に答える 2

3

プログラミング Ruby から:

カウント enum.count {| オブジェクト | ブロック } → int

obj と等しい、またはブロックが true 値を返す enum 内のオブジェクトの数を返します。

そのため、列挙子は各要素にアクセスし、ブロックが true を返した場合 (この場合、要素が配列インデックスと等しい場合)、カウントに 1 を追加します。

このパターンがあまり使用されているのを見たことがありません (あったとしても)。

[4, 1, 2, 0].each_with_index.select { |elem, index| elem == index }.count

編集

あなたのコメントから例を見てみましょう:

[4, 1, 2, 0].enum_for(:each_slice, 2).map do |a, b|
  a + b
end

each_slice(2)配列を一度に 2 要素取り、各スライスの配列を返します。

[4, 1, 2, 0].each_slice(2).map # => [[4,1], [2,0]]

結果を呼び出すmapと、各サブ配列を操作してブロックに渡すことができます。

[4, 1, 2, 0].enum_for(:each_slice, 2).map do |a,b|
  puts "#{a.inspect} #{b.inspect}"
end

結果は

4 1
2 0

abブロック引数が「スプラッティング」されているため、それらの値を取得します。

a, b = *[4, 1]
a # => 4
b # => 1

代わりに配列スライスを引数として取ることもできます:

[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| puts "#{a.inspect}"}

[4, 1]
[2, 0]

これを行うことができます:

[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| a.inject(:+) } #=> [5,2]

または、ActiveSupport (Rails アプリなど) をお持ちの場合は、

[4, 1, 2, 0].enum_for(:each_slice, 2).map {|a| a.sum }

これは、元の例よりもはるかに明確に思えます。

于 2012-11-12T20:14:04.053 に答える
0

array.count通常はブロックを取ることができますが、それ自体では fixnum を返すため、.with_index他のイテレータ ( tryarray.map.with_index {|x,i ... }など) のようにチェーンすることはできません。

.enum_for(:count)それを列挙子に変換し、その連鎖を可能にします。配列のメンバーを 1 回反復し、インデックスと等しいメンバーの数を集計します。したがって、 count は実際には一度だけ呼び出されますが、配列をより柔軟なものに変換した後にのみ呼び出されます。

于 2012-11-12T19:58:03.363 に答える