在Ruby中减去两个哈希值

时间:2014-07-08 21:22:00

标签: ruby hash

是否可以修改hash类,以便给定两个哈希值,可以创建一个只包含一个哈希中但不包含另一个哈希值的新哈希值?

E.g:

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

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

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

可选地,difference方法可以包括任何键/值对,使得键存在于两个哈希中,但它们之间的值不同。

5 个答案:

答案 0 :(得分:12)

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

案例1:将所有键/值对k=>v保留在h1 k h2的{​​{1}}中>

这是一种方式:

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}
Ruby 2.0中引入了

Array#to_h。对于早期版本,请使用Hash[]

答案 1 :(得分:6)

使用reject方法:

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

如果值相同,则仅拒绝键/值对(根据mallanaga的建议,通过对原始答案的评论,我已将其删除):

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

答案 2 :(得分:2)

你可以这样做:

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

答案 3 :(得分:0)

尝试使用hashdiff gem。

diff=HashDiff.diff(h1,h2)

答案 4 :(得分:0)

对于深层嵌套,您可以添加一些递归,例如(未嵌套)

class Hash
  def -(h2)
    raise ArgumentError unless h2.is_a?(Hash)
    h1 = dup
    h1.delete_if do |k, v|
      if v.is_a?(Hash) && h2[k].is_a?(Hash)
        h1[k] = v - h2[k]
        h1[k].blank?
      else
        h2[k] == v
      end
    end
   end
  end
end