[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
私はこのコードを見ていますが、脳は10がどのように結果になるかを記録していません。ここで何が起こっているのか誰かが説明してもらえますか?
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
私はこのコードを見ていますが、脳は10がどのように結果になるかを記録していません。ここで何が起こっているのか誰かが説明してもらえますか?
回答:
最初のブロック引数はアキュムレータと考えることができます。ブロックの各実行の結果はアキュムレータに格納され、次にブロックの次の実行に渡されます。上記のコードの場合、アキュムレータの結果をデフォルトで0にしています。ブロックを実行するたびに、指定した数値が現在の合計に追加され、結果がアキュムレータに格納されます。次のブロック呼び出しは、この新しい値を持ち、それに追加し、再び格納して、繰り返します。
プロセスの最後に、injectはアキュムレータを返します。これは、この場合、配列内のすべての値の合計、つまり10です。
以下は、オブジェクトの配列からハッシュを作成する別の簡単な例です。オブジェクトの文字列表現をキーにしています。
[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end
この場合、デフォルトでアキュムレータを空のハッシュに設定し、ブロックが実行されるたびにそれを生成します。ブロックの結果はアキュムレータに戻されるため、ハッシュをブロックの最後の行として返す必要があることに注意してください。
result + explanation
、アキュムレータへの変換と戻り値の両方です。これは、ブロックの最後の行であり、暗黙的に戻ります。
inject
(0
例では)で始まる値とブロックを受け取り、リストの要素ごとにそのブロックを1回実行します。
result + element
)を保存します。これを説明する最も簡単な方法は、例として、各ステップがどのように機能するかを示すことです。これは、この結果を評価する方法を示す架空の手順のセットです。
[1, 2, 3, 4].inject(0) { |result, element| result + element }
[2, 3, 4].inject(0 + 1) { |result, element| result + element }
[3, 4].inject((0 + 1) + 2) { |result, element| result + element }
[4].inject(((0 + 1) + 2) + 3) { |result, element| result + element }
[].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element }
(((0 + 1) + 2) + 3) + 4
10
injectメソッドの構文は次のとおりです。
inject (value_initial) { |result_memo, object| block }
上記の例、つまり
[1, 2, 3, 4].inject(0) { |result, element| result + element }
これは出力として10を与えます。
だから、始める前に、各変数に格納されている値が何であるかを見てみましょう:
結果= 0ゼロは0であるinject(value)から取得されました
element = 1配列の最初の要素です。
オーケー!!!だから、上の例を理解してみましょう
ステップ1 [1, 2, 3, 4].inject(0) { |0, 1| 0 + 1 }
ステップ2 [1, 2, 3, 4].inject(0) { |1, 2| 1 + 2 }
ステップ:3 [1, 2, 3, 4].inject(0) { |3, 3| 3 + 3 }
ステップ:4 [1, 2, 3, 4].inject(0) { |6, 4| 6 + 4 }
ステップ:5 [1, 2, 3, 4].inject(0) { |10, Now no elements left in the array, so it'll return 10 from this step| }
ここで、太字の斜体の値は配列からフェッチした要素であり、太字の単純な値は結果の値です。
の#inject
メソッドの動作をご理解いただければ幸いです#ruby
。
彼らが言ったこと、しかしあなたは必ずしも「開始値」を提供する必要がないことに注意してください:
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
と同じです
[1, 2, 3, 4].inject { |result, element| result + element } # => 10
試して、待ってみます。
injectに引数が渡されない場合、最初の2つの要素が最初の反復に渡されます。上記の例では、最初はresultが1でelementが2であるため、ブロックへの呼び出しが1つ少なくなります。
注入はブロックを適用します
result + element
配列内の各項目に。次の項目(「要素」)の場合、ブロックから返される値は「結果」です。(パラメーターを使用して)呼び出した方法では、「結果」はそのパラメーターの値から始まります。したがって、効果は要素を追加することです。
tldr; inject
はmap
、1つの重要な点で異なります。inject
ブロックの最後の実行の値をmap
返しますが、反復した配列を返します。
それ以上に、各ブロック実行の値は最初のパラメーター(result
この場合)を介して次の実行に渡され、その値((0)
部分)を初期化できます。
上記の例は次のように書くことができますmap
:
result = 0 # initialize result
[1, 2, 3, 4].map { |element| result += element }
# result => 10
同じ効果ですが、inject
ここではより簡潔です。
map
ブロックで評価が発生するのに対して、割り当てはブロックで発生することがよくありますinject
。
どの方法を選択するかは、目的のスコープによって異なりますresult
。使用しない場合は次のようになります。
result = [1, 2, 3, 4].inject(0) { |x, element| x + element }
「いいね、私はそれをすべて1行にまとめただけ」のように思われるかもしれませんが、一時的にメモリを一時x
変数として割り当てたので、すでにresult
作業している必要はありませんでした。
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
以下と同等です。
def my_function(r, e)
r+e
end
a = [1, 2, 3, 4]
result = 0
a.each do |value|
result = my_function(result, value)
end
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
単純な英語では、この配列([1,2,3,4]
)を通過(反復)しています。4つの要素(1、2、3、および4)があるため、この配列を4回反復します。injectメソッドには1つの引数(数値0)があり、その引数を最初の要素(0 +1。これは1に等しい)に追加します。「結果」に1件保存されます。次に、その結果(1)を次の要素(1 + 2、これは3)に追加します。これは結果として保存されます。続ける:3 + 3は6に等しい。そして最後に、6 + 4は10に等しい。
ここから始めて、ブロックを取るすべてのメソッドを確認してください。 http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject
あなたを混乱させるのはブロックですか、それともなぜメソッドに価値があるのですか?良い質問ですが。そこでの演算子メソッドは何ですか?
result.+
それは何から始まりますか?
#inject(0)
できますか?
[1, 2, 3, 4].inject(0) { |result, element| result.+ element }
これは機能しますか?
[1, 2, 3, 4].inject() { |result = 0, element| result.+ element }
私は、配列のすべての要素を単純に合計し、ドキュメントに表示されるメモに数値を生成するという考えに基づいて構築しています。
あなたはいつでもこれを行うことができます
[1, 2, 3, 4].each { |element| p element }
配列の列挙可能オブジェクトが反復処理されるのを確認します。それが基本的な考え方です。
注入または削減が送信されるメモまたはアキュムレータを与えるだけです。
結果を得ようとすることができます
[1, 2, 3, 4].each { |result = 0, element| result + element }
何も戻らないので、これは以前と同じように機能します
[1, 2, 3, 4].each { |result = 0, element| p result + element }
要素インスペクターブロック内。
これはシンプルで理解しやすい説明です。
「初期値」は最初はややわかりにくいので忘れてください。
> [1,2,3,4].inject{|a,b| a+b}
=> 10
上記は次のように理解できます。私は1、2、3、4の間に「追加マシン」を挿入しています。つまり、1♫2♫3♫4であり、♫は加算マシンであるため、1 + 2 + 3 + 4と同じであり、10です。
あなたは実際に+
それらの間にインジェクションすることができます:
> [1,2,3,4].inject(:+)
=> 10
これは、+
1、2、3、4の間にa を挿入し、1 + 2 + 3 + 4にして10にするというものです。これ:+
は、Ruby +
がシンボルの形式で指定する方法です。
これは非常に理解しやすく、直感的です。そして、それが段階的にどのように機能するかを分析したい場合、それは次のようなものです:1と2を取り、それらを追加して、結果が得られたら、最初に格納し(3)、次に、格納されます値3と配列要素3はa + bプロセスを通過します。これは6であり、この値を格納し、6と4はa + bプロセスを通過し、10になります。
((1 + 2) + 3) + 4
「初期値」0
は、そもそも「ベース」にすぎません。多くの場合、それは必要ありません。1 * 2 * 3 * 4が必要で、それが
[1,2,3,4].inject(:*)
=> 24
そしてそれが行われます。1
全体を乗算するための「初期値」は必要ありません1
。
.inject()メソッドには別の形式があります。これは非常に役立ちます[4,5] .inject(&:+)これは、領域のすべての要素を合計します