如何查找包含匹配值的哈希键

238

假设我有以下clients哈希表,有没有一种快速的ruby方法(而不必编写多行脚本)来获取键名,以便匹配client_id?例如: 如何获取client_id == "2180"的键名?

clients = {
  "yellow"=>{"client_id"=>"2178"}, 
  "orange"=>{"client_id"=>"2180"}, 
  "red"=>{"client_id"=>"2179"}, 
  "blue"=>{"client_id"=>"2181"}
}
11个回答

476

Ruby 1.9及以上版本:

hash.key(value) => key

Ruby 1.8:

你可以使用 hash.index

hsh.index(value) => key

返回给定值的键。如果找不到,返回nil

h = { "a" => 100, "b" => 200 }
h.index(200) #=> "b"
h.index(999) #=> nil

因此,要获取"orange",只需使用:

clients.key({"client_id" => "2180"})

2
如果哈希表有多个键,那么这将变得有些混乱,因为您需要将整个哈希表传递给index - Daniel Vandersluis
55
Ruby 1.9中,Hash#index方法被重命名为Hash#key - Vikrant Chaudhary
14
请注意,此代码仅返回第一个匹配项。如果有多个哈希对具有相同的值,则它将返回第一个具有匹配值的键。 - Mike Campbell

195
你可以使用Enumerable#select方法。
clients.select{|key, hash| hash["client_id"] == "2180" }
#=> [["orange", {"client_id"=>"2180"}]]

请注意,结果将是一个包含所有匹配值的数组,其中每个值都是键和值的数组。


26
findselect 的区别在于,find 返回第一个匹配项,而 select(别名为 findAll)返回所有匹配项。 - Daniel Vandersluis
我明白了,所以在存在多个匹配项的情况下,这将是更安全的选择。 - Coderama
1
这比创建一个全新的哈希表(通过调用“invert”)来查找一个项要好。 - Hejazi
4
请注意,从Ruby 1.9.3开始,这将返回一个包含匹配项的新哈希表。它不会像Ruby <= 1.8.7中那样返回一个数组。`clients.select{|key, hash| hash["client_id"] == "2180" }

=> {"orange"=>{"client_id"=>"2180"}}`

- AndrewS
要获取键(key),只需输入 clients.select{|key, hash| hash["client_id"] == "2180" }.keys - Mirror318

50
你可以反转哈希表。 clients.invert["client_id"=>"2180"] 返回 "orange"

3
这似乎也是一个聪明的方式(因为它很简短)来完成它! - Coderama
这是我需要的用于表单数组(用于选择框)创建反向哈希的内容。 - Joseph Le Brech

24
您可以使用hashname.key(valuename)方法。
或者,也可以进行反向操作。使用hashname.invert方法将返回一个新的哈希表new_hash,您可以更加传统地使用它。

3
这是在 Ruby 近期版本(1.9+)中正确的做法。 - Lars Haugseth
1
在这种情况下,#invert 是一个非常糟糕的想法,因为你实际上是为了查找一个键而分配了一块可丢弃的哈希对象的内存。根据哈希大小,它将会对性能产生严重的影响。 - Dr.Strangelove

20

试试这个:

clients.find{|key,value| value["client_id"] == "2178"}.first

5
如果查找返回 nil,这将抛出异常,因为不能在 nil 上调用 .first。 - Schrockwell
1
如果使用Rails,您可以使用.try(:first)而不是.first来避免异常(如果您预计该值可能会丢失)。 - aaron-coding
2
Ruby 2.3.0 + 中,您可以在块末尾使用safe navigator &.first来防止空值异常。 - Gagan Gami

14

6

从文档中得知:

  • (对象?) detect(如果没有=nil) {|obj| ... }
  • (对象?) find(如果没有=nil) {|obj| ... }
  • (对象) detect(如果没有=nil)
  • (对象) find(如果没有=nil)

将枚举中的每个条目传递给块。 返回第一个不为false的块。 如果没有对象匹配,则调用ifnone并在指定时返回其结果,否则返回nil。

如果未提供块,则返回枚举器。

(1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35

这对我有用:

这对我有用:

clients.detect{|client| client.last['client_id'] == '2180' } #=> ["orange", {"client_id"=>"2180"}] 

clients.detect{|client| client.last['client_id'] == '999999' } #=> nil 

See: http://rubydoc.info/stdlib/core/1.9.2/Enumerable#find-instance_method


4

寻找特定值的键的最佳方法是使用哈希可用的键方法....

gender = {"MALE" => 1, "FEMALE" => 2}
gender.key(1) #=> MALE

我希望它能解决你的问题...


2

另一种我会尝试的方法是使用 #map

clients.map{ |key, _| key if clients[key] == {"client_id"=>"2180"} }.compact 
#=> ["orange"]

这将返回给定值的所有出现次数。下划线表示我们不需要携带键的值,因此它不会被分配给变量。如果值不匹配,则数组将包含nils-这就是为什么我在末尾放置#compact的原因。

1
这是一种简单的方法,可以找到给定值的键:
    clients = {
      "yellow"=>{"client_id"=>"2178"}, 
      "orange"=>{"client_id"=>"2180"}, 
      "red"=>{"client_id"=>"2179"}, 
      "blue"=>{"client_id"=>"2181"}
    }

    p clients.rassoc("client_id"=>"2180")

...并找到给定键的值:

    p clients.assoc("orange") 

它将会给你键值对。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接