カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

Rubyでハッシュの値の比較を行う

どうやるか分からなかったので。ハッシュ同士ではなく、値の比較をしたいとき。 2つのハッシュがあって、キーが同じなのに値が違うとか、そもそもキーがないとか。そういうとき。

ActiveSupportでは、以下のようなオープンクラス?が用意されていて、diffの例も載っている。 URLはこれ

class Hash
  # Returns a hash that represents the difference between two hashes.
  #
  #   {1 => 2}.diff(1 => 2)         # => {}
  #   {1 => 2}.diff(1 => 3)         # => {1 => 2}
  #   {}.diff(1 => 2)               # => {1 => 2}
  #   {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
  def diff(other)
    ActiveSupport::Deprecation.warn "Hash#diff is no longer used inside of Rails, and is being deprecated with no replacement. If you're using it to compare hashes for the purpose of testing, please use MiniTest's assert_equal instead."
    dup.
      delete_if { |k, v| other[k] == v }.
      merge!(other.dup.delete_if { |k, v| has_key?(k) })
  end
end

あとは、適当に。

hash1.diff(hash2)

とかすればいい。

わけですが、上記diffメソッドだけを抜き出して、def hash_diff()にしてもいいのですが、もっといいやり方があると教えて頂きました。

# -*- encoding: utf-8 -*-
hash_a = {'/data/test001.json'=>'12345', '/data/test002.json'=>'123456', '/data/json003.json' => '123'}
hash_b = {'/data/test001.json'=> '123456', '/data/test002.json' => '123456', '/data/json004.json' => '11'}

puts "--differences--"
p hash_b.reject{ |k, v| v == hash_a[k] }.keys

rejectメソッドで、条件に一致するものを除いて、リストが返ってくるので、keysでキーだけ取得。

出力はこんな感じ。

--differences--
["/data/test001.json", "/data/json004.json"]

valueが違う「/data/test001.json」と、そもそもhash_aにキーとして存在しない「/data/json004.json」が抽出できる。

コード劇的に短くなりましたな。。。力不足。。。