Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 循环通过散列数组_Ruby - Fatal编程技术网

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开始