Цикл по массиву хэшей - PullRequest
0 голосов
/ 28 марта 2019

У меня есть массив хэшей:

@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 для первого экземпляра, в котором он не найдет совпадение.

Любая помощь приветствуется.

Ответы [ 3 ]

5 голосов
/ 28 марта 2019

Если проблема в том, что вы возвращаетесь слишком рано, тогда вы можете просто воздержаться от возвращения рано. Это должно работать:

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
1 голос
/ 28 марта 2019

Как указал Дэвид Грейсон, прямой ответ - вы возвращаетесь слишком рано.

Потенциально лучшим решением является использование хеша хешей, а не массива хешей, основанного на id как ключ.Это было бы гораздо более эффективным, чем поиск в цикле, а также заставило бы вас столкнуться с тем фактом, что в ваших данных есть дубликаты id.

@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, это просто обычный хеш-доступ.Также обратите внимание, что это возвращает nil, если соответствующий id не найден, как требуется.

0 голосов
/ 28 марта 2019

Если вы выполняете много таких вызовов «find one», лучше индексировать список, преобразовав его в хеш:

indexed_candidates = candidates.index_by { |obj| obj[:id] }

def find(id)
  indexed_candidates[id]
end

Это O (1) время для вызова find,вместо O (N), чтобы циклически проходить через него каждый раз.

Однако это зависит от того, что список кандидатов является статическим, если вам нужно добавить / удалить, вам нужно перестроить или обновить индекс.

РЕДАКТИРОВАТЬ

Поскольку было указано, что index_by не в ядре ruby ​​(вам просто нужно require 'active_support/all, однако), если вы используете ruby ​​2.4 или новее, вы можете использоватьtransform_values:

indexed_candidates = candidates
  .group_by { |obj| obj[:id] }
  .transform_values(&:first)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...