比较红宝石中的两个相似的哈希值

时间:2010-09-21 19:36:11

标签: ruby-on-rails ruby ruby-1.8

我正在使用ruby 1.8.7并且我需要比较我拥有的两个哈希,它们本质上是模型的属性。散列A小于散列B,散列B具有散列A的所有属性,加上一些我不关心的额外属性。我的首要目标是查看A的元素是否与B的相应元素相同。例如

@hash_a = {:cat => 'Bubby', :dog => 'Gizmo'}  
@hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
@hash_a == @hash_b
#=> true

现在它变得有点复杂了,因为这些字段完全不匹配,即使它们依赖于同一条信息

@hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'}  
@hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
@hash_a == @hash_b
#=> true

我正在研究的是一个比较两个匹配项的过程,如果字段已更改,则更新它,并且仅在它们发生更改时更新。或者如果找不到匹配的项目,则创建一个新项目。更改散列本身的名称不是一种选择。目前我只是在私有方法中比较每个字段,看它们是否相等。

return hash_a[:cat] == hash_b[:cats_name] && hash_a[:dog] == hash_b[:dog] 

我觉得必须有更好的方法,我正在寻找比这更快更优雅的东西。

4 个答案:

答案 0 :(得分:3)

如果将哈希值转换为数组,则可以像这样比较它们。

@hash_a.to_a == (@hash_a.to_a & @hash_b.to_a)

如果您愿意,也可以在散列类中的方法后面隐藏此代码:

class Hash
  def diff_equal(other)
    to_a == (to_a & other.to_a)
  end
end

然后像@hash_a.diff_equal(@hash_b)一样使用它。如果您选择了该路径,则可能需要检查其他是哈希值还是响应to_a方法。

答案 1 :(得分:1)

嘿,如果你真的想要快速和优雅,那么你去吧:

(a = @hash_a.values; (a & @hash_b.values) == a)

有一些明显的局限性......

答案 2 :(得分:1)

我是这样做的:

def eql hash1, hash2, rewire = {}
  map = Hash.new {|h, key| rewire[key] || key}
  !hash1.any? do |key, val| 
    hash2[map[key]] != val
  end
end


hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'}  
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
p eql(hash_a, hash_b) #=> false

hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'}  
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
p eql(hash_a, hash_b, :cats_name => :cat)  #=> true


hash_a = {:cat => 'Bubby', :dog => 'Gizmo'}  
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
p eql(hash_a, hash_b) #=> true

hash_a = {:cat => 'Bubby', :dog => 'Gizmo', :fish => "Wanda"}  
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  
p eql(hash_a, hash_b) #=> false

不会太久,似乎也像你想要的那样工作:)

答案 3 :(得分:0)

一种可能性是首先重新映射一个散列的密钥,然后执行设置子集操作:

require 'set'

def remap_keys(hash, key_map)
  hash.inject({}) do |acc, pair|
    key, value = pair
    remapped_key = key_map[key] || key
    acc[remapped_key] = value
    acc
  end
end

def hash_subset?(a, b)
  set_a = Set.new(a)
  set_b = Set.new(b)
  set_a.subset?(set_b)
end

hash_a = {:cats_name => 'Bubby', :dog => 'Gizmo'}  
hash_b = {:cat => 'Bubby', :dog => 'Gizmo', :lion => 'Simba'}  

puts hash_subset?(remap_keys(hash_a, {:cats_name => :cat}), hash_b)

但是,我确信有更有效的方法可以做到这一点。不止一种方法来:cat,呃?!