ハッシュの配列を単一のハッシュにマッピングするRails


91

私は次のようなハッシュの配列を持っています:

 [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

そして、私はこれを次のような単一のハッシュにマッピングしようとしています:

{"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

私はそれを使ってそれを達成しました

  par={}
  mitem["params"].each { |h| h.each {|k,v| par[k]=v} } 

しかし、これをより慣用的な方法で(できればローカル変数を使用せずに)実行できるかどうか疑問に思っていました。

これどうやってするの?

回答:


159

あなたが作ってEnumerable#reduce、あなたがHash#merge望むものを達成することができます。

input = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
input.reduce({}, :merge)
  is {"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

配列の各要素の間にメソッド呼び出しを貼り付けるような並べ替えを減らします。

たとえば、[1, 2, 3].reduce(0, :+)言っ0 + 1 + 2 + 3て与えるようなもの6です。

私たちのケースでは、似たようなことを行っていますが、2つのハッシュをマージするmerge関数を使用しています。

[{:a => 1}, {:b => 2}, {:c => 3}].reduce({}, :merge)
  is {}.merge({:a => 1}.merge({:b => 2}.merge({:c => 3})))
  is {:a => 1, :b => 2, :c => 3}

1
ありがとう、これは素晴らしい答えです:)とてもうまく説明されました!
Bart Platak 2012

40
input.reduce(&:merge)で十分です。
redgetan 2014

@redgetanはそれと何か違うのinput.reduce(:merge)ですか?
David van Geest、

1
@David van Geest:この場合、それらは同等です。ここで使用する単項アンパサンドは、シンボルからブロックを構築します。ただし、reduceには、記号を受け入れる特別なケースがあります。例を単純化するために単項アンパサンド演算子を避けたかったのですが、この場合、初期値はオプションであるため、redgetanは正しいです。
cjhveal

1
merge!代わりに使用した場合merge、最初のハッシュは変更されますが(望ましくない場合があります)、新しいマージごとに中間ハッシュは作成されません。
Phrogz 2016年

50

どうですか:

h = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
r = h.inject(:merge)

このスキームは、Joshuaの回答と実質的に同じですが、すべてのハッシュに#merge(メソッド名はシンボルとして渡されます)を繰り返し適用します(injectは、アイテム間に演算子を挿入することと考えてください)。#injectを参照してください
重屋2012

2
h.inject(&:merge)のように、アンパサンドが必要ないのはなぜですか?
Donato

5
injectメソッドは、メソッド名としても解釈されるパラメータをシンボルとして受け入れるためです。インジェクトの特徴です。
重屋

9

#injectを使用

hashes = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
merged = hashes.inject({}) { |aggregate, hash| aggregate.merge hash }
merged # => {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}

0

ここでは、Enumerableクラスからの注入または削減の両方を使用できます。これらは両方とも互いのエイリアスであるため、どちらにもパフォーマンス上の利点はありません。

 sample = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

 result1 = sample.reduce(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.