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

我希望能够减去两个哈希并在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 

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

任何帮助,将不胜感激。

如何将哈希转换为集合。

 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) #=> # 

作为推荐……

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

 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”,则会遇到问题,因为规范化会踩到一个。

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

 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" 

我得到了resque 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} 

这次我想提供另一种解决方案:规范化 – >存储原始键值对 – >获取具有较大值的原始键作为差异的关键。

 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) # create a hash which contains all normalized keys all_pairs = (self.keys.map{|x| x.downcase} + subtrahend.keys.map{|x| x.downcase}).uniq.inject({}) do |pairs, key| pairs[key] = [] pairs end #=> {"mouse"=>[], "cat"=>[], "snake"=>[], "bird"=>[], "dog"=>[]} # push original key value pairs into array which is the value of just created hash [self, subtrahend].each_with_index do |hsh, idx| hsh.each_pair { |k, v| all_pairs[k.downcase].push([k, v]) } all_pairs.each_value { |v| v.push([nil, 0]) if v.size == idx } end #=> {"mouse"=>[[nil, 0], ["Mouse", 75]], "cat"=>[["Cat", 100], ["cat", 50]], "snake"=>[["Snake", 10], ["Snake", 10]], "bird"=>[["Bird", 2], ["BIRD", 4]], "dog"=>[["Dog", 5], ["dog", 3]]} results = {} all_pairs.each_value do |values| diff = values[0][1] - values[1][1] # always take the key whose value is larger if diff > 0 results[values[0][0]] = diff elsif diff < 0 results[values[1][0]] = diff end end return results end end puts h1.difference(h2).inspect #=> {"Cat" => 50, "Dog" => 2, "BIRD" => -2, "Mouse" => -75} h1.difference(h2) == h3 ? puts("Pass") : puts("Fail") #=> "Pass" 

根据你所描述的,这个做得很好。 结果正是您所显示的内容(键在最终结果中未标准化,但取决于其值更大)。