Ruby on rails 比较ruby中两个相似的哈希

Ruby on rails 比较ruby中两个相似的哈希,ruby-on-rails,ruby,ruby-1.8,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

我使用的是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] 

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

一种可能是首先重新映射一个哈希的键,然后执行一个集合子集操作:

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)
然而,我相信有更有效的方法来做到这一点。给猫剥皮的方法不止一种:猫,嗯

嘿,如果你真的想快速优雅,那就来吧:

(a = @hash_a.values; (a & @hash_b.values) == a)
有一些明显的限制…

以下是我的做法:

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

不会太长,而且似乎也能像您所希望的那样工作:)

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

@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\u a.diff\u equal(@hash\u b)
一样使用它。如果您选择了该路径,您可能希望检查另一个路径是否是散列或是否响应
to_a
方法。

但这不会忽略键吗?如果{:cat=>'Gizmo',:dog=>'Bubby'}哦,您可能需要对结果进行排序,尽管您的示例数据不需要排序。您的目标是什么?比较代码的简单性?效率/速度?这可以进一步简化。(a-b)如果a是b的子集,则返回空数组。