我有2个哈希,比方说A,B
A: { 'key1' => [a, b], 'key2' => 'c' }
B: { 'key1' => [b, a], 'key2' => 'c' }
比较这两个哈希的最佳方法是什么。数组内容的顺序无关紧要。所以在我的情况下,哈希A和B相等
答案 0 :(得分:2)
这并不像乍看起来那样容易。
有必要考虑几个细微差别:
一个相对通用的解决方案如下:
def hashes_comp(hash1, hash2)
return false if hash1.size != hash2.size
hash1.each do |key, value|
if value.class == Array
return false if hash2[key].class != Array || value.sort != hash2[key].sort
else
return false if value != hash2[key]
end
end
true
end
hash_a = {'key1' => ['a', 'b'], 'key2' => 'c'}
hash_b = {'key1' => ['b', 'a'], 'key2' => 'c'}
hash_c = {'key1' => ['a', 'c'], 'key2' => 'c'}
hash_d = {'key1' => ['a', 'b'], 'key2' => 'd'}
hash_e = {'key1' => ['a', 'b'], 'key2' => ['a', 'b']}
hash_f = {'key1' => ['a', 'b'], 'key2' => 'c', 'key3' => 'd'}
hashes_comp(hash_a, hash_b) #=> true
hashes_comp(hash_a, hash_c) #=> false
hashes_comp(hash_a, hash_d) #=> false
hashes_comp(hash_a, hash_e) #=> false
hashes_comp(hash_a, hash_f) #=> false
答案 1 :(得分:1)
一个人可以对数组进行排序,但是如果数组很大,那将是一个昂贵的操作。如果n
等于数组的大小,则堆排序的时间复杂度例如为O(n log(n))
。用计数哈希代替数组更快,其构造的时间复杂度为O(n)
。
h1 = { 'k1' => [1, 2, 1, 3, 2, 1], 'k2' => 'c' }
h2 = { 'k1' => [3, 2, 1, 2, 1, 1], 'k2' => 'c' }
def same?(h1, h2)
return false unless h1.size == h2.size
h1.all? do |k,v|
if h2.key?(k)
vo = h2[k]
if v.is_a?(Array)
if vo.is_a?(Array)
convert(v) == convert(vo)
end
else
v == vo
end
end
end
end
def convert(arr)
arr.each_with_object(Hash.new(0)) { |e,g| g[e] += 1 }
end
same?(h1, h2)
#=> true
这里
convert([1, 2, 1, 3, 2, 1])
#=> {1=>3, 2=>2, 3=>1}
convert([3, 2, 1, 2, 1, 1])
#=> {3=>1, 2=>2, 1=>3}
和
{1=>3, 2=>2, 3=>1} == {3=>1, 2=>2, 1=>3}
#=> true
请参见Hash::new,特别是该方法采用等于默认值的参数的情况。
保护子句return false unless h1.size == h2.size
用于确保h2
不具有h1
中不存在的密钥。请注意,以下内容返回伪造的值nil
:
if false
#...
end
#=> nil
在一些地方,我写的是这样,而不是更冗长但等效的表达式
if false
#...
else
nil
end
答案 2 :(得分:0)
我肯定会同意Ivan,这并不像最初看起来那样容易,但是我认为我会尝试递归地进行。这样做还有一个好处,就是可以比较散列以外的内容。
hash_a = {'key1' => ['a', 'b'], 'key2' => 'c'}
hash_b = {'key1' => ['b', 'a'], 'key2' => 'c'}
hash_c = {'key1' => ['a', 'c'], 'key2' => 'c'}
hash_d = {'key1' => ['a', 'b'], 'key2' => 'd'}
hash_e = {'key1' => ['a', 'b'], 'key2' => ['a', 'b']}
hash_f = {'key1' => ['a', 'b'], 'key2' => 'c', 'key3' => 'd'}
def recursive_compare(one, two)
unless one.class == two.class
return false
end
match = false
# If it's not an Array or Hash...
unless one.class == Hash || one.class == Array
return one == two
end
# If they're both Hashes...
if one.class == Hash
one.each_key do |k|
match = two.key? k
break unless match
end
two.each_key do |k|
match = one.key? k
break unless match
end
if match
one.each do |k, v|
match = recursive_compare(v, two[k])
break unless match
end
end
end
# If they're both Arrays...
if one.class == Array
one.each do |v|
match = two.include? v
break unless match
end
two.each do |v|
match = one.include? v
break unless match
end
end
match
end
puts recursive_compare(hash_a, hash_b) #=> true
puts recursive_compare(hash_a, hash_c) #=> false
puts recursive_compare(hash_a, hash_d) #=> false
puts recursive_compare(hash_a, hash_e) #=> false
puts recursive_compare(hash_a, hash_f) #=> false
答案 3 :(得分:0)
我想出了这个解决方案:
def are_equals?(a, b)
(a.keys.sort == b.keys.sort) &&
a.merge(b) { |k, o_val, n_val| [o_val, n_val].all? { |e| e.kind_of? Array} ? o_val.sort == n_val.sort : o_val == n_val }.values.all?
end
第一部分使用Hash#keys
测试键是否相等,该键返回键数组,其排序方式当然是:
a.keys.sort == b.keys.sort
对于第二部分,我使用Hash#merge
比较与同一键相关的值,并且可以通过以下方式进行扩展:
res = a.merge(b) do |k, o_val, n_val|
if [o_val, n_val].all? { |e| e.kind_of? Array}
o_val.sort == n_val.sort
else
o_val == n_val
end
end
#=> {"key1"=>true, "key2"=>true}
它返回一个哈希值(其中值是true或false),然后使用Enumerable#all?
检查所有值是否都为true:
res.values.all?
#=> [true, true].all? => true