Steven Kwok Steven Kwok - 4 months ago 28x
Ruby Question

Count how many times something appears in an array?

This is the array that is going to be processed:

[{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]

and I would like the result to be like this:

[{:name => "blake", :count => 2}, {:name => "ashley", :count => 1}]

I created a new hash called "count" then i used .each to iterate through the array and then count[:count] += 1 but it's not giving me what I'm looking for.


It can be done with built-in library calls like this:

a = [{:name => "blake"}, {:name => "blake"}, {:name => "ashley"}]
a.group_by(&:itself)                   # group all of the identical elements together
 .map{|k, v| k.merge(count: v.length)} # add the "count" element to the hash


.group_by(&:itself) will take all the identical components and put them in a hash together under the same key:

>> h = a.group_by(&:itself)
=> {
     {:name=>"blake"}  => [{:name=>"blake"}, {:name=>"blake"}],
     {:name=>"ashley"} => [{:name=>"ashley"}]

Notice how the first entry in the hash has an array of two identical elements, and the second entry has an array of one element. To create counts of those, we can use the .length method on the arrays in the hash's values:

>> k, v = h.first
>> v
=> [{:name=>"blake"}, {:name=>"blake"}]

>> v.length
=> 2

Then we can use .map to apply that code to every element in the hash:

>>{|k, v| [k, v.length]}.to_h
=> {

Finally, .merge will take two hashes and piece them together into a single hash:

>> {:name=>"blake"}.merge({:count => 1})
=> {:name=>"blake", :count=>1}