如何在Ruby中按哈希值搜索哈希数组?

276

我有一个哈希数组,@fathers。

a_father = { "father" => "Bob", "age" =>  40 }
@fathers << a_father
a_father = { "father" => "David", "age" =>  32 }
@fathers << a_father
a_father = { "father" => "Batman", "age" =>  50 }
@fathers << a_father 

我该如何搜索此数组,并返回其中满足条件的哈希数组?

比如:

@fathers.some_method("age" > 35) #=> array containing the hashes of bob and batman
谢谢。

6
这个问题非常有用,但我不禁想知道为什么会需要一个 @fathers 数组:P。 - ARK
@ARK 我稍微被那个问题分心了一下,但我的注意力完全被这个认识给吸引住了:在 @fathers 哈希里的每个元素都有一个 'father' 键而不是一个 'name' 键。我希望我能相信这些是父亲的父亲,但我不能。 - cesoid
4个回答

480
你需要使用 Enumerable#select 方法(也称为 find_all):
@fathers.select {|father| father["age"] > 35 }
# => [ { "age" => 40, "father" => "Bob" },
#      { "age" => 50, "father" => "Batman" } ]

根据文档,该方法“返回一个包含所有枚举元素(在这种情况下为@fathers)中块不为false的元素的数组。”


26
哦!你是第一个!删除了我的回答并点了赞。 - Milan Novota
31
请注意,如果您只想找到第一个符合条件的父亲,可以使用 @fathers.find {|father| father["age"] > 35 } - Leigh McCulloch
1
能否返回在原始哈希数组中找到的位置索引? - Ian Warner
1
@IanWarner 是的。我建议查看 Enumerable 模块的文档。如果你仍然无法弄清楚,可以发布一个新的问题。 - Jordan Running
1
我刚刚执行了这个操作:index = ARRAY.index {|h| h[:code] == ARRAY["code"]} - Ian Warner
使用唯一哈希值,没有条件,条件是 father["unique_id"] == 35 而不是 >,我们使用唯一ID而不是年龄,那么找到它的最快方法是什么?有什么建议吗?我想找出具有该ID的父亲。 - user1735921

222

这将返回第一个匹配项

@fathers.detect {|f| f["age"] > 35 }

7
我更喜欢这个选项而不是 #select - 但这取决于你的使用情况。如果没有匹配项,#detect 将返回 nil,而在 @Jordan 的答案中,#select 将返回 [] - TJ Biddle
16
为了让代码更易读,你也可以使用find替换detect - Alter Lagos
8
在Rails中,find可能会让人感到困惑。 - user12341234
8
“select”和“detect”并不相同,“select”将遍历整个数组,而“detect”会在找到第一个匹配项后停止。如果你只想寻找一个匹配项, @fathers.select {|f| f["age"] > 35 }.first@fathers.detect {|f| f["age"] > 35 }相比, 就性能和可读性而言,我倾向于选择“detect”。 - Naveed

45

如果你的数组长这样

array = [
 {:name => "Hitesh" , :age => 27 , :place => "xyz"} ,
 {:name => "John" , :age => 26 , :place => "xtz"} ,
 {:name => "Anil" , :age => 26 , :place => "xsz"} 
]

如果您想知道某个值是否已经存在于数组中,请使用Find方法。

array.find {|x| x[:name] == "Hitesh"}

如果"name"中包含"Hitesh",则返回对象,否则返回nil。


1
如果名称像“hitesh”一样是小写的,它将不会返回哈希值。在这种情况下,我们如何考虑单词大小写呢? - arjun
2
array.find {|x| x[:name].downcase == "Hitesh".downcase } - Hitesh Ranaut
@arjun array.any?{ |element| element[:name].casecmp("hitesh")==0 } 应该适用于字符串的任何大小写,例如 "Hitesh", "hitesh" 或者 "hiTeSh" - ARK
实际上请检查我的答案:https://dev59.com/K3E95IYBdhLWcg3wlu-z#63375479 - ARK
finddetect 方法的别名。 - netwire

7

(补充之前的回答(希望能帮助到某些人):)

年龄更简单,但在字符串中忽略大小写:

  • 仅验证是否存在:

@fathers.any? { |father| father[:name].casecmp("john") == 0 } 可以适用于开始或任何位置的大小写,例如 "John""john""JoHn" 等。

  • 查找第一个实例/索引:

@fathers.find { |father| father[:name].casecmp("john") == 0 }

  • 选择所有这样的索引:

@fathers.select { |father| father[:name].casecmp("john") == 0 }


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