Ruby哈希检查是子集?

ma1*_*w28 16 ruby hash subset contain

如何判断Ruby散列是否是(或包含)另一个散列的子集?

例如:

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}
hash.include_hash?({})            # true
hash.include_hash?({f: 6, c: 3})  # true
hash.include_hash?({f: 6, c: 1})  # false
Run Code Online (Sandbox Code Playgroud)

Mar*_*pka 16

我想到的解决方案使用Hash#merge方法:

class Hash
  def include_hash?(hash)
    merge(hash) == self
  end
end

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}
hash.include_hash?({})
# => true
hash.include_hash?(f: 6, c:3)
# => true
hash.include_hash?(f: 6, c:1)
# => false
Run Code Online (Sandbox Code Playgroud)

  • 对于嵌套哈希,你可以使用`active support`的[deep_merge](http://apidock.com/rails/Hash/deep_merge) (2认同)

小智 14

从Ruby 2.3开始,您还可以执行以下操作来检查这是否是一个子集

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}
{} <= hash           # true
{f: 6, c: 3} <= hash # true
{f: 6, c: 1} <= hash # false
Run Code Online (Sandbox Code Playgroud)


Car*_*and 8

数组差异似乎最简单:

class Hash
  def include_hash?(h)
    (h.to_a - to_a).empty?
  end
end

h = {a: 1, b: 2}
h.include_hash?({b: 2}) #=> true
h.include_hash?({b: 3}) #=> false
Run Code Online (Sandbox Code Playgroud)

  • @Arup,我恭敬地不同意,但我知道你的观点被许多其他人所共享.Imo,`self.to_a`表明这里需要`self`(就像它后面跟着一个存取器或`class`一样).我认为最好避免在不需要时使用`self`.如果一个读者对`to_a`感到困惑而没有'self`,他们会很快弄明白,并在讨价还价中学到一些东西. (3认同)

tor*_*o2k 7

您可以将哈希值转换为集合,然后使用方法subset?superset?(或它们各自的别名<=>=)执行检查:

require 'set'

hash.to_set.superset?({}.to_set)
# => true

hash.to_set >= {a: 1}.to_set
# => true

{a: 2}.to_set <= hash.to_set 
# => false
Run Code Online (Sandbox Code Playgroud)

更新:建议解决方案的基准:

require 'fruity'
require 'set'

hash = ('aa'..'zz').zip('aa'..'zz').to_h
# {"aa"=>"aa", "ab"=>"ab", ...
find = ('aa'..'zz').zip('aa'..'zz').select { |k, _| k[0] == k[1] }.to_h 
# {"aa"=>"aa", "bb"=>"bb", ...

compare(
  toro2k:        -> { hash.to_set >= find.to_set },
  MarekLipka:    -> { hash.merge(find) == hash },
  CarySwoveland: -> { (find.to_a - hash.to_a).empty? },
  ArupRakshit:   -> { arr = hash.to_a; find.all? { |pair| arr.include?(pair) } }
)
Run Code Online (Sandbox Code Playgroud)

结果:

Running each test 2 times. Test will take about 1 second.
MarekLipka is faster than toro2k by 3x ± 0.1
toro2k is faster than CarySwoveland by 39.99999999999999% ± 10.0%
CarySwoveland is faster than ArupRakshit by 1.9x ± 0.1
Run Code Online (Sandbox Code Playgroud)

  • 哇我只是想感谢你向我介绍[果味宝石](https://github.com/marcandre/fruity)!棒极了. (2认同)

Aru*_*hit 6

你可以做 :

def include_hash?(hash,subset_hash)
   arr = hash.to_a
   subset_hash.all? { |pair| arr.include?(pair) }
end
Run Code Online (Sandbox Code Playgroud)