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


198

鉴于我具有以下客户哈希,是否有一种快速的红宝石方法(无需编写多行脚本)来获取给定的我想要匹配client_id的密钥?例如,如何获取密钥client_id == "2180"

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

Answers:


176

您可以使用Enumerable#select

clients.select{|key, hash| hash["client_id"] == "2180" }
#=> [["orange", {"client_id"=>"2180"}]]

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


22
@Coderama find和之间的区别在于,selectfind返回第一个匹配项,而select(由别名findAll)返回所有匹配项。
Daniel Vandersluis 2010年

我知道,因此对于不止一个匹配项的实例,这将是更安全的选择。
Coderama

1
这比创建一个invert仅用于查找项目的全新哈希(通过调用)要好。
Hejazi 2013年

3
请注意,从Ruby 1.9.3开始,这将返回带有匹配项的新哈希。它不会像在Ruby <= 1.8.7中那样返回数组。 clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS 2014年

要获取密钥,只需将clients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318 '17

407

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 2010年

51
Hash#index被重命名为Hash#keyRuby 1.9中
维克兰特乔杜里

12
请注意,这只会返回第一个匹配项,如果存在多个具有相同值的哈希对,它将返回具有匹配值的第一个键。
Mike Campbell


22

您可以使用hashname.key(valuename)

或者,可以按顺序进行反转。new_hash = hashname.invert将为您提供一个new_hash让您更传统地做事的方法。


3
这是在Ruby的最新版本(1.9+)中执行此操作的正确方法。
Lars Haugseth

#invert在这种情况下,这是一个非常糟糕的主意,因为您本质上是为了寻找密钥而为一次性哈希对象分配内存。根据哈希大小,它会严重影响性能
Dr.Strangelove

15

试试这个:

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

4
如果find返回nil,则将引发异常,因为您不能在nil上调用.first。
Schrockwell

1
如果使用Rails,可以使用.try(:first)而不是.first避免异常(如果您期望值可能会丢失)。
aaron编码

2
Ruby 2.3.0 +你可以使用安全的导航仪 &.first在块的结尾从无异常来阻止
加甘加米


6

从文档:

  • (对象?)detect(ifnone = nil){| obj | ...}
  • (对象?)find(ifnone = nil){| obj | ...}
  • (对象)detect(ifnone = nil)
  • (对象)查找(ifnone = 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 

请参阅:http//rubydoc.info/stdlib/core/1.9.2/Enumerable#find-instance_method



2

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

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

这将返回所有给定值的事件。下划线表示我们不需要携带键的值,这样就不会将其分配给变量。如果值不匹配,则数组将包含nil,这就是为什么我放在#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") 

它将为您提供键值对。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.