Looping through an array of hashes

array of hashes ruby
ruby hash
ruby array of hashes get value
ruby iterate over hash
ruby select value from array of hashes
ruby iterate over array
iterate through array of hashes in ruby
ruby hash map

I have an array of hashes:

@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
  },
]

I am trying to take an argument id and return a hash within @candidates whose value for :id matches id. If no match is found, it returns nil.

My method looks like this:

def find(id)
  for candidate in @candidates
    if candidate[:id] == id
      return candidate
    else
      return nil
    end
  end
end

find(15)

This however returns nil as soon as it finishes with the first item in the array. It should continue to the end of the array and find all matches, and if it finds none, return nil, not simply return nil for the first instance it doesn't find a match.

Any help is appreciated.

If the problem is that you are returning too early, then you can simply refrain from returning early. This should work:

def find(id)
  for candidate in @candidates
    if candidate[:id] == id
      return candidate 
    end
  end
  nil
end

But a nicer way to do it would be:

def find(id)
  @candidates.find { |c| c[:id] == id }
end

How do I iterate over an array of hashes and return the values in a , Understand Ruby Hashes and common Ruby Hash methods. We also cover how to iterate over a hash and how to compare Array vs Hash in Ruby. For each key in my hash, I would like to loop through each element of the array, assign that to a scalar variable so that I can process it, then move onto the next element of the array. Once I have processed all the elements of the array for a key, I want to onto the next key and individually process all of the elements of its array, and so on.

As pointed out by David Grayson, the direct answer is you're returning too early.

A potentially better solution is to use a hash of hashes rather than an array of hashes, based on the id as the key. This would be far more efficient than a loop-based search for lookup, and would also force you to confront the fact that you have duplicate ids in your data.

@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

Note that you don't need a find method, it's just a normal hash access. Also note that this returns nil if a matching id is not found, as desired.

Ruby Hashes - A Detailed Guide, Iterating over a Hash. You can use the each method to iterate over all the elements in a Hash. However unlike Array#each , when� Looping Through a Nested Hash The best way to understand a nested loop is this: the first iteration loops through the outer hash and its key/value pair, and the second iteration loops through the inner hash and its key/value pair.

If you are running many such "find one" calls it's better performance to index the list by transforming it to a hash:

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

def find(id)
  indexed_candidates[id]
end

This is O(1) time to call find, versus O(N) to loop through it each time.

However this depends on the candidates list being static, if you need to add / remove you would need to rebuild or update the index.

EDIT

Since it was pointed out that index_by is not in ruby core (you just have to require 'active_support/all, though) if you are using ruby 2.4 or newer you can use transform_values:

indexed_candidates = candidates
  .group_by { |obj| obj[:id] }
  .transform_values(&:first)

Ruby Primer - Hashes, in and out., Arrays aren't the only Ruby type that get to see the benefits of iteration. In Ruby Collections, we learned about arrays and hashes. Hashes have several different � # Example 3: Iterate through an array of hashes # You are given an array of hashes called "users" which comprises of 3 hashes: user1, user2, user3

Hash Iteration | Ruby Loops, Learn about arrays and hashes, including how to iterate over these data structures. In Ruby, an array is an ordered collection of Ruby objects separated by� A PowerShell hash table can not iterate a loop on it’s own What I didn’t realize was that a hashtable is actually a single PowerShell object. It’s not an actual collection like I’m used to.

Arrays and Hashes, Iterate over the contacts hash and when you reach the key : favorite_ice_cream_flavors , remove "strawberry" from the Array of Freddy's favorite ice cream flavors. Looping through an array with C How to loop through an array with C. Published Feb 10, 2020. One of the main use cases of arrays is to be used along with loops.

Nested Hash Iteration Code Along, I have 4 hash tables and I want to loop through array and then through each hash table. Array of Hashes: @array = (%hash0, %hash1, %hash2� Answer: There are at least two ways to loop over all the elements in a Perl hash. You can use either (a) a Perl foreach loop, or (b) a Perl while loop with the each function. I find the Perl foreach syntax easier to remember, but the solution with the while loop and the each function is preferred for larger hashes. A Perl hash/foreach example

Comments
  • Why not set it up as a hash of hashes rather than an array of hashes, where each hash is accessed by the id? You would avoid the need to loop and get your result in constant time. Also, since you're looking things up by id, you clearly don't need to store it inside the hash so you're free to make it the index without having redundancy.
  • you can do this with the index_by method as i show in my answer.
  • @maxpleaner Not in plain Ruby. index_by is a rails method.
  • You're right, I thought one of the newer Rubies has added it but I was thinking of transform_keys/transform_values.
  • Interestingly, group_by is in ruby core, so you could do .group_by { |obj| obj[:id] }.transform_values(&:first) since 2.4