a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']] a.inject({}) {|r, val| r[値[0]] = 値[1]}
これを実行すると、インデックスエラーが発生します
ブロックを
a.inject({}) {|r, val| r[val[0]] = val[1]; r}
その後、動作します。
ルビーは、私が望むものを得られない最初の注入試行をどのように処理していますか?
これを行うより良い方法はありますか?
a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']] a.inject({}) {|r, val| r[値[0]] = 値[1]}
これを実行すると、インデックスエラーが発生します
ブロックを
a.inject({}) {|r, val| r[val[0]] = val[1]; r}
その後、動作します。
ルビーは、私が望むものを得られない最初の注入試行をどのように処理していますか?
これを行うより良い方法はありますか?
Ruby が動的かつ暗黙的に型付けされているからといって、型について考える必要がないわけではありません。
Enumerable#inject
明示的なアキュムレータを持たない の型(これは通常 と呼ばれreduce
ます) は、次のようなものです。
reduce :: [a] → (a → a → a) → a
または、私が作成したよりRubyっぽい表記で
Enumerable[A]#inject {|A, A| A } → A
すべてのタイプが同じであることがわかります。の要素の型Enumerable
、ブロックの 2 つの引数の型、ブロックの戻り値の型、およびメソッド全体の戻り値の型。
明示的なアキュムレータ (これは通常 と呼ばれます) をEnumerable#inject
持つの型は、次のfold
ようなものです。
fold :: [b] → a → (a → b → a) → a
また
Enumerable[B]#inject(A) {|A, B| A } → A
ここでは、accumulator がコレクションの要素の型とは異なる型を持つことができることがわかります。
これらの 2 つの規則により、通常、関連するすべてのEnumerable#inject
型の問題を解決できます。
この場合、あなたを悩ませているのはルール 1 です。あなたが何かをするとき
acc[key] = value
あなたのブロックでは、割り当ては、割り当ての受信者ではなく、割り当てられた値に評価されます。これを次のように置き換える必要があります
acc.tap { acc[key] = value }
なぜ Ruby の inject メソッドは初期値なしで文字列の長さを合計できないのですか?も参照してください。
ところで: 分解バインドを使用して、コードをより読みやすくすることができます。
a.inject({}) {|r, (key, value)| r[key] = value; r }
もっと簡単な方法があります -
a = [[1, 'a'],[2, 'b'],[3, 'c'], [4, 'd']]
b = Hash[a] # {1=>"a", 2=>"b", 3=>"c", 4=>"d"}
最初の方法が機能しない理由は、inject がブロックの結果をr
次の反復で使用するためです。最初の反復でr
は、 は渡された引数に設定されます。この場合は{}
です。
最初のブロックは代入の結果を に戻しinject
、2 番目のブロックはハッシュを返すため、実際に機能します。
多くの人がinject
アンチパターンのこの使用法を検討しています。each_with_object
代わりに検討してください。
a.inject({}) { |r, val| r.merge({ val[0] => val[1] }) }