Rubyで重複したキーを上書きせずに2つのハッシュをマージするにはどうすればよいですか?


140

重複するキーを上書きせずに2つのハッシュをマージする簡単またはエレガントな方法はありますか?

つまり、キーが元のハッシュに存在する場合、その値を変更したくありません。


本当に配列(例:['a'、 'b'、 'c'])またはハッシュ(例:{'a' => 1、 'b' => 2、 'c' => 3})を意味しますか? ?
Alex Reisner、

申し訳ありませんが、私はハッシュについて話していました:)
Claudio Acciaresi

回答:


232

2つのハッシュとがoptionsありdefaults、既存のキーを上書きせずににマージdefaultsoptionsたい場合、本当にやりたいのはその逆です:merge optionsinto defaults

options = defaults.merge(options)

または、Railsを使用している場合は、次のことができます。

options.reverse_merge!(defaults)

完全に同意します。reverse_mergeに感謝します。メソッドはそれを知りませんでした:)
Claudio Acciaresi

なぜここに括弧が必要なのですか?表示されるdefault.mergeオプションを実行することはできません。
Donato

1
reverse_merge!Rails 5.1のセキュリティの問題のため、非推奨になりました
Mirv-Matt

@ Mirv-Matt-減価償却の通知が表示されません。apidock.com/rails/v6.0.0/Hash/reverse_merge%21
Kshitij

17

標準のRubyライブラリには、既存の値を上書きしたり、ハッシュを再割り当てしたりせずにハッシュをマージする方法があります。

important_hash.merge!(defaults) { |key, important, default| important }

3

元のハッシュと2番目のハッシュの両方に重複したキーがあり、どちらの方向にも上書きしたくないという問題がある場合は、なんらかの衝突チェックと処理を伴う単純な手動マージを行わなければならない場合があります。

hash2.each_key do |key|
  if ( hash1.has_key?(key) )
       hash1[ "hash2-originated-#{key}" ] = hash2[key]
  else
       hash1[key]=hash2[key]
  end
end

明らかに、これは非常に初歩的なものであり、hash1には「hash2-originated-whatever」と呼ばれるキーがないことを前提としています。まだhash1に含まれていないもの。また、数か月間ルビーを実行していないので、おそらく構文的に正しくありませんが、要点を理解できるはずです。

または、キーの値を配列として再定義して、hash1 [key]がhash1からの元の値とhash2からの値を返すようにします。あなたがあなたの結果が本当になりたいものに依存します。


両方のキーを保持せず、同じキーの値を合計する場合はどうでしょうか?
トムKCチウ2015年

1
@ TomK.C.Chiuこれは、質問から判断できない状況に大きく依存します-hash1の値が文字列で、hash2が整数の場合はどうなりますか?実行可能なオプションである場合もありますが、より頻繁に問題が発生する場合があります。値にリストを使用することを提案することで、これを問題なく回避できます。
glenatron、2015年

0

ここで2つのハッシュをマージできます reverse_merge

order = {
 id: 33987,
 platform: 'web'
}

user = {
  name: 'Jhon Doe',
  email: 'jhon.doe@gmail.com' 
}
newHash = oder.reverse_merge!(user)
render json: { data: newHash, status: 200 }

0

あなたは2つのハッシュをマージしたい場合optionsdefaults、宛先ハッシュを上書きせずに、あなたがチェックしてselectキーが既に先のハッシュに存在している場合。Railsを使用しない純粋なRubyソリューションを次に示します。

options  = { "a" => 100, "b" => 200 }
defaults = { "b" => 254, "c" => 300 }
options.merge!(defaults.select{ |k,_| not options.has_key? k })

# output
# => {"a"=>100, "b"=>200, "c"=>300}

または、キーは存在するが、それを含みnil、それを上書きしたい場合:

options.merge!(defaults.select{ |k,_| options[k].nil? })
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.