Вычесть два хэша в Ruby

может hash класс можно изменить так, чтобы при наличии двух хэшей можно было создать новый хэш, содержащий только ключи, присутствующие в одном хэше, но не в другом?

например:

h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}

h2 = {"Cat" => 100, "Dog" => 5, "Bison" => 30}

h1.difference(h2) = {"Bird" => 2, "Snake" => 10}

дополнительно difference метод может включать любые пары ключ / значение, такие что ключ присутствует в обоих хэшах, но значение отличается между ними.

4 ответов


h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}
h2 = {"Cat" => 999, "Dog" => 5, "Bison" => 30}

Случай 1: сохранить все пары ключ / значение k=>v на h1 для которого нет ключа k на h2

это один из способов:

h1.dup.delete_if { |k,_| h2.key?(k) }
  #=> {"Bird"=>2, "Snake"=>10}

вот еще:

class Array
  alias :spaceship :<=>
  def <=>(o)
    first <=> o.first
  end
end

(h1.to_a - h2.to_a).to_h
  #=> {"Bird"=>2, "Snake"=>10}

class Array
  alias :<=> :spaceship
  remove_method(:spaceship)
end

случай 2: Держите все пары ключ / значение в h1, не h2

все, что вам нужно для этого:

(h1.to_a - h2.to_a).to_h
  #=> {"Cat"=>100, "Bird"=>2, "Snake"=>10}

массив#to_h был представлен в Ruby 2.0. Для более ранних версий используйте хэш - [].


использовать reject способ:

class Hash
  def difference(other)
    reject do |k,v|
      other.has_key? k
    end
  end
end

отклонять только пары ключ / значение, если значения идентичны (согласно Малланагапредложение через комментарий к моему первоначальному ответу, который я удалил):

class Hash
  def difference(other)
    reject do |k,v|
      other.has_key?(k) && other[k] == v
    end
  end
end


вы можете сделать это:

h2.each_with_object(h1.dup){|(k, v), h| h.delete(k)}

попробуйте использовать hashdiff gem.

diff=HashDiff.diff(h1,h2)