Ruby 循环通过散列数组
我有一个哈希数组:Ruby 循环通过散列数组,ruby,Ruby,我有一个哈希数组: @candidates = [ { id: 15, years_of_experience: 4, github_points: 293, languages: ['C', 'Ruby', 'Python', 'Clojure'], age: 26 }, { id: 7, years_of_experience: 1, github_points: 145, languages: ['Java
@candidates = [
{
id: 15,
years_of_experience: 4,
github_points: 293,
languages: ['C', 'Ruby', 'Python', 'Clojure'],
age: 26
},
{
id: 7,
years_of_experience: 1,
github_points: 145,
languages: ['JavaScript', 'Ruby', 'Go', 'Erlang'],
age: 19
},
{
id: 9,
years_of_experience: 6,
github_points: 435,
languages: ['JavaScript', 'SQL', 'C#'], age: 32
},
{
id: 11,
years_of_experience: 3,
github_points: 232,
languages: ['Java', 'Ruby', 'JavaScript'],
age: 31
},
{
id: 11,
years_of_experience: 12,
github_points: 32,
languages: ['VB', 'Cobol', 'Fortran'],
age: 42
},
{
id: 13,
years_of_experience: 2,
github_points: 328,
languages: ['Python', 'Ruby', 'JavaScript'],
age: 25
},
{
id: 15,
years_of_experience: 1,
github_points: 400,
languages: ['JavaScript', 'Ruby'],
age: 16
},
]
我试图获取一个参数id
,并在@candidates
中返回一个哈希值,其:id
的值与id
匹配。如果未找到匹配项,则返回nil
我的方法如下所示:
def find(id)
for candidate in @candidates
if candidate[:id] == id
return candidate
else
return nil
end
end
end
find(15)
但是,一旦完成数组中的第一项,它将返回nil
。它应该继续到数组的末尾并查找所有匹配项,如果没有找到匹配项,则返回nil
,而不是简单地返回nil
,因为它首先没有找到匹配项
感谢您的帮助。如果问题是您返回得太早,那么您可以简单地避免过早返回。这应该起作用:
def find(id)
for candidate in @candidates
if candidate[:id] == id
return candidate
end
end
nil
end
但更好的方法是:
def find(id)
@candidates.find { |c| c[:id] == id }
end
如果您正在运行许多这样的“find one”调用,那么通过将列表转换为散列来索引列表会有更好的性能:
indexed_candidates = candidates.index_by { |obj| obj[:id] }
def find(id)
indexed_candidates[id]
end
这是O(1)次调用find
,而不是O(N)次循环
但是,这取决于候选列表是静态的,如果需要添加/删除,则需要重建或更新索引
编辑
由于有人指出,index\u by
不在ruby core中(但您只需要求“活动\u支持/all
),如果您使用ruby 2.4或更新版本,您可以使用转换\u值
:
indexed_candidates = candidates
.group_by { |obj| obj[:id] }
.transform_values(&:first)
正如大卫·格雷森所指出的,直接的答案是你回来得太早了 一个可能更好的解决方案是使用散列而不是散列数组,基于
id
作为键。这将比基于循环的查找更有效,还将迫使您面对数据中存在重复的id
s这一事实
@candidates = {
15 => {
years_of_experience: 4,
github_points: 293,
languages: ['C', 'Ruby', 'Python', 'Clojure'],
age: 26
},
7 => {
years_of_experience: 1,
github_points: 145,
languages: ['JavaScript', 'Ruby', 'Go', 'Erlang'],
age: 19
},
9 => {
years_of_experience: 6,
github_points: 435,
languages: ['JavaScript', 'SQL', 'C#'], age: 32
},
11 => {
id: 11,
years_of_experience: 3,
github_points: 232,
languages: ['Java', 'Ruby', 'JavaScript'],
age: 31
},
'11a' => { # note that you have two 11's!
years_of_experience: 12,
github_points: 32,
languages: ['VB', 'Cobol', 'Fortran'],
age: 42
},
13 => {
years_of_experience: 2,
github_points: 328,
languages: ['Python', 'Ruby', 'JavaScript'],
age: 25
},
'15a' => { # ditto for 15's
years_of_experience: 1,
github_points: 400,
languages: ['JavaScript', 'Ruby'],
age: 16
},
}
p @candidates[15] # => {:years_of_experience=>4, :github_points=>293, :languages=>["C", "Ruby", "Python", "Clojure"], :age=>26}
p @candidates[42] # => nil
注意,您不需要
find
方法,它只是一个普通的散列访问。还请注意,如果未根据需要找到匹配的id
,则返回nil
。为什么不将其设置为散列而不是散列数组,其中每个散列由id访问?这样可以避免循环,并在固定时间内得到结果。此外,由于您是按id查找内容的,显然不需要将其存储在散列中,这样您就可以在没有冗余的情况下自由地将其作为索引。您可以使用index\u by
方法执行此操作,正如我在回答中所示。@maxpleaner不是在纯Ruby中index\u by
是一种rails方法。你是对的,我以为一个较新的Rubies添加了它,但我想到了transform\u键/transform\u值。有趣的是,group\u by
在ruby内核中,所以你可以做。group\u by{obj | obj[:id]}。transform\u值(&:first)
从2.4开始