检测哈希中是否存在键值对

Detecting if a key-value pair exists within a hash

我找不到确定哈希中是否存在键值对的方法。

h4 = { "a" => 1, "d" => 2, "f" => 35 }

我可以使用 Hash#has_value?Hash#has_key? 分别查找有关键或值的信息,但如何检查是否存在一对?

我所追求的伪代码:

if h4.contains_pair?("a", 1)

只需使用这个:

h4['a'] == 1

这对我来说似乎太过分了,但你可以用这样的方法对 Hash 进行猴子修补:

class Hash
  def contains_pair?(key, value)
    key?(key) && self[key] == value
  end
end

如何使用枚举any?

h4 = { "a" => 1, "d" => 2, "f" => 35 }
h4.any? {|k,v| k == 'a' && v == 1 }

我承认开始走一条路,然后想知道它会把我带到哪里。这可能不是确定散列中是否存在 key/value 对的最佳方法(如何改进@Jordan 的回答?),但我在此过程中学到了一些东西。

代码

def pair_present?(h,k,v)
  Enumerable.instance_method(:include?).bind(h).call([k,v])
end

例子

h = { "a"=>1, "d"=>2, "f"=>35 }

pair_present?(h,'a',1)
  #=> true

pair_present?(h,'f',36)
  #=> false

pair_present?(h,'hippopotamus',2)
  #=> false

讨论

我们当然可以将散列转换为数组,然后应用 Array#include?:

h.to_a.include?(['a', 1])
  #=> true

但这有创建临时数组的缺点。如果 class Hash 有这样的实例方法就好了,但它没有。有人可能认为 Hash#include? 可能用于此目的,但它只需要一个参数,一个键。1.

方法 Enumerable#include? 做我们想要的,当然 Hash includeEnumerable 模块。我们可以通过多种方式调用该方法。

Enumerable#include?绑定到哈希并调用它

这当然是我的回答:

Enumerable.instance_method(:include?).bind(h).call([k,v])

使用v2.2中引入的方法Method#super_method

h.method(:include?).super_method.call(['a',1])
  #=> true
h.method(:include?).super_method.call(['a',2])
  #=> false

注意:

h.method(:include?).super_method
  #=> #<Method: Object(Enumerable)#include?>

alias_method/remove_method旋转木马

Hash.send(:alias_method, :temp, :include?)
Hash.send(:remove_method, :include?)
h.include?(['a',1])
  #=> true
h.include?(['a',2])
  #=> false
Hash.send(:alias_method, :include?, :temp)
Hash.send(:remove_method, :temp)

将散列转换为枚举器并调用Enumerable#include?

h.to_enum.include?(['a',1])
  #=> true
h.to_enum.include?(['a',2])
  #=> false

这是有效的,因为 class Enumeratorincludes Enumerable

1 Hash#include?Hash#key? and Hash#has_key? 相同。这让我想知道为什么 include? 不用于当前目的,因为确定哈希是否具有给定密钥已被很好地覆盖。