Reputation: 29817
I have this array of hashes:
- :name: Ben
:age: 18
- :name: David
:age: 19
- :name: Sam
:age: 18
I need to group them by age
, so they end up like this:
18:
- :name: Ben
:age: 18
- :name: Sam
:age: 18
19:
- :name: David
:age: 19
I tried doing it this way:
array = array.group_by &:age
but I get this error:
NoMethodError (undefined method `age' for {:name=>"Ben", :age=>18}:Hash):
What am I doing wrong? I'm using Rails 3.0.1 and Ruby 1.9.2
Upvotes: 46
Views: 51972
Reputation: 31477
The &:age
means that the group_by
method should call the age
method on the array items to get the group by data. This age
method is not defined on the items that are Hashes in your case.
This should work:
array.group_by { |d| d[:age] }
Also with newer Ruby versions you can use the following shortcut:
array.group_by { _1[:age] }
_1
here reflects the first positional argument of the block passed to the #group_by
method.
Upvotes: 116
Reputation: 9175
As others have pointed out ruby's Symbol#to_proc
method is invoked and calls the age
method on each hash in the array. The problem here is that the hashes do not respond to an age
method.
Now we could define one for the Hash class, but we probably don't want it for every hash instance in the program. Instead we can simply define the age
method on each hash in the array like so:
array.each do |hash|
class << hash
def age
self[:age]
end
end
end
And then we can use group_by
just as you were before:
array = array.group_by &:age
Upvotes: 0
Reputation: 5330
out = {}
array_of_hashes.each do |a_hash|
out[a_hash[:age]] ||= []
out[a_hash[:age]] << a_hash
end
or
array.group_by {|item| item[:age]}
Upvotes: 1