Hash#mergeにおけるkeyの重複チェック

 rubyでは、異なる2つのHashをmergeするときに、重複するkeyがあっても上書きされて、特にエラーになったりはしません。
ただ重複が無いはずのHashデータをmergeする場合、仮に重複keyがあればmergeでエラーとなって欲しいので、key重複のチェック方法について検討したメモ書き

重複keyチェック

P.S. 6/18


と下記のように、Setを使ってkeyの重複を調べようと当初考えたが、重複時の動作をblock使うと制御できるのでそれでよい気がするw−、
むやみに、require 'set'もしなくてよいしw−、、、


てか、Hashクラスにモンキーパッチ充てるまでもない気もするので、普通の関数で、以下でどうでしょう?

def merge_strict a,b
  a.merge(b){|key,l,r| raise "key duplicate"}
rescure => e
  p e
  nil
end

P.P.S. 6/18


コメントで、Setに変換せず、そのままArray#&を使えば?っと指摘を受けるが、そうですね、そのままでいいですね^^;


モンキーパッチ版も以下のように簡単になりますね。

class Hash
  def merge_strict other
    unless (self.keys & other.keys).empty?
      nil
    else
      self.merge(other)
    end
  end
end

基本は、Hash#keysで取り出したkey配列をSetに変換し、共通集合が有るかどうかを確認することで、重複チェックが思いついたのでそのようにモンキーパッチーw−


p RUBY_VERSION     #=>"2.1.5"

class Hash
  def merge_strict other
    require 'set'
    
    unless (Set[*self.keys] & Set[*other.keys]).empty?
      nil
    else
      self.merge(other)
    end
  end
end

a =  {a: 1, b: 2}
b =  {c: 3, d: 4}
aa = {a: "foo", aa: "bar", aaa: "baz"}

a.merge b           #=> {:a=>1, :b=>2, :c=>3, :d=>4}
a.merge aa          #=> {:a=>"foo", :b=>2, :aa=>"bar", :aaa=>"baz"}

a.merge_strict b    #=> {:a=>1, :b=>2, :c=>3, :d=>4}
a.merge_strict aa   #=> nil

まあ期待通りうごいてる。重複エラーはnilでなく例外起こしたほうが良いか?
ってかメソッド内部で、requireは良いのだろうか*1

APIリファレンス参考

Set#intersection

class Set (Ruby 2.1.0)

モンキーパッチ

あまりにあまりなモンキーパッチなので、モダンなモンキーパッチを学ばナイト><

分別のあるRubyモンキーパッチャーになるために

メタプログラミング

メタちからを取り戻さないと><

メタプログラミングRuby 第2版
Paolo Perrotta
オライリージャパン
売り上げランキング: 26,971

*1:他に方法思いつかなかった