从另一个哈希中的相应值中减去哈希值

时间:2012-08-14 18:18:53

标签: ruby hash

我希望能够减去两个哈希并在Ruby中获得第三个哈希值。

这两个哈希看起来像这样:

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

h2 = {"cat" => 50, "dog" => 3, "BIRD" => 4, "Mouse" => 75, "Snake" => 10}
h2.default = 0

我希望能够在h1上调用这样的方法:

h1.difference(h2)

并获得此哈希值:

{"Cat" => 50, "Dog" => 2, "BIRD" => -2, "Mouse" => -75}

我想创建一个新散列,其中包含来自两个散列的键和新散列的值,作为第一个散列中键的值减去第二个散列中该键的值。问题是,无论密钥的情况如何,我都希望这种Hash方法能够正常工作。换句话说,我希望“猫”与“猫”匹配。

这是我到目前为止所拥有的:

class Hash
  def difference(another_hash)
    (keys + another_hash.keys).map { |key| key.strip }.uniq.inject(Hash.new(0)) { |acc, key| acc[key] = (self[key] - another_hash[key]); acc }.delete_if { |key, value| value == 0 }
  end
end

这没关系,但不幸的是,结果并不是我想要的。

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:4)

如何将哈希值转换为集合。

require 'set'

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

h2 = {"cat" => 50, "dog" => 3, "BIRD" => 4, "Mouse" => 75, "Snake" => 10}
h2.default = 0

p (h1.to_set - h2.to_set)
#=> #<Set: {["Cat", 100], ["Dog", 5], ["Bird", 2]}>

答案 1 :(得分:3)

作为推荐......

我过去曾经使用过这样的东西:

class Hash
  def downcase_keys
    Hash[map{ |k,v| [k.downcase, v]}]
  end

  def difference(other)
    Hash[self.to_a - other.to_a]
  end
  alias :- :difference
end

让我做的事情如下:

irb(main):206:0> h1.downcase_keys - h2.downcase_keys
{
     "cat" => 100,
     "dog" => 5,
    "bird" => 2
}
irb(main):207:0> h2.downcase_keys - h1.downcase_keys
{
      "cat" => 50,
      "dog" => 3,
     "bird" => 4,
    "mouse" => 75
}

alias为您提供了使用-代替difference的良好语法,类似于使用-进行数组和集合。您仍然可以使用difference

irb(main):210:0> h1.downcase_keys.difference(h2.downcase_keys)
{
     "cat" => 100,
     "dog" => 5,
    "bird" => 2
}
irb(main):211:0> h2.downcase_keys.difference(h1.downcase_keys)
{
      "cat" => 50,
      "dog" => 3,
     "bird" => 4,
    "mouse" => 75
}

我总是规范化我的哈希键,并且不允许变量泄漏。当你不知道键被调用时,它会使哈希处理太困难,所以我强烈建议你这样做。第一步。这是一个代码维护问题。

否则,您可以创建原始键名称及其规范化名称的映射,但如果您的哈希包含两个唯一大小写键,例如“key”和“KEY”,则会遇到问题,因为规范化将会踩踏之一。

答案 2 :(得分:0)

很抱歉,由于时间限制(我现在必须照顾我的男婴),只知道这个愚蠢但正常工作的代码:

h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}
h1.default = 0
h2 = {"cat" => 50, "dog" => 3, "BIRD" => 4, "Mouse" => 75, "Snake" => 10}
h2.default = 0
h3 = {"Cat" => 50, "Dog" => 2, "BIRD" => -2, "Mouse" => -75}

class Hash
  def difference(subtrahend)
    diff = {}
    self.each_pair do |k1, v1|
      flag = false
      subtrahend.each_pair do |k2, v2|
        if k1.downcase == k2.downcase
          flag = true
          v_diff = v1 - v2
          break if v_diff == 0
          v_diff > 0 ? diff[k1] = v_diff : diff[k2] = v_diff
        end
      end
      diff[k1] = v1 unless flag
    end
    subtrahend.each_pair do |k2, v2|
      flag = false
      self.each_pair do |k1, v1|
        if k1.downcase == k2.downcase
          flag = true
          break
        end
      end
      diff[k2] = -v2 unless flag
    end
    return diff
  end
end

h1.difference(h2) == h3 ? puts("Pass") : puts("Fail") #=> "Pass"

答案 3 :(得分:0)

我得到了救援https://github.com/junegunn/insensitive_hash

然后按照您的程序进行调整,但需要稍加调整

require 'insensitive_hash'

h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10}.insensitive
h1.default = 0

h2 = {"cat" => 50, "dog" => 3, "BIRD" => 4, "Mouse" => 75, "Snake" => 10}.insensitive
h2.default = 0


class Hash
  def difference(another_hash)
    (keys + another_hash.keys).map { |key|
      key.downcase }.uniq.inject(Hash.new(0)) do |acc, key|
      val = self[key] - another_hash[key]
      acc[key] = val if val!= 0
      acc
    end
  end
end

h1.difference(h2)
# => {"cat"=>50, "dog"=>2, "bird"=>-2, "mouse"=>-75}