【问题标题】:Detecting if a key-value pair exists within a hash检测哈希中是否存在键值对
【发布时间】:2016-06-30 05:58:25
【问题描述】:

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

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

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

我所追求的伪代码:

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

【问题讨论】:

  • 这个值可以是nil吗?
  • 感谢sawa 的留言! Jordan 已经解决了这两种情况。

标签: ruby hash key-value


【解决方案1】:

就用这个吧:

h4['a'] == 1

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

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

【讨论】:

  • 哎呀,我以为你只能用那种语法设置哈希值——没想到要尝试==。我希望你不会看到这个线程乔丹......现在你知道我真的是一个菜鸟。我会尽快将您的答案标记为正确,因为它是最简洁的。
  • 乔丹,你有空看看stackoverflow.com/questions/39951060/…漂亮吗?我在一个对我来说很重要的项目上碰壁了,几天后我对 SO 没有任何反应。
  • @sawa 对该问题的评论暗示如果v 可以等于nil,则h[k] == v 不起作用。
【解决方案2】:

如何使用 Enumerable any?

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

【讨论】:

  • 当我们可以在 O(1) 时间内直接访问密钥时,遍历整个 Hash 似乎有点奇怪。
【解决方案3】:

我承认从一条路开始,然后想知道它会带我去哪里。这可能不是确定哈希中是否存在键/值对的最佳方法(如何改进@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

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

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

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

这当然是我的回答:

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

使用方法Method#super_method,在v2.2中引入。

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

这是有效的,因为 Enumerator 类也是 includes Enumerable

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

【讨论】:

  • 哇,好东西。我很高兴我问了这个问题而不是回避它,因为我认为它太简单了。这真是个好东西,谢谢 Cary!
猜你喜欢
  • 2013-02-18
  • 2012-08-10
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
相关资源
最近更新 更多