user1531875
user1531875

Reputation: 49

How do I get the unique elements and count from an array of hashes in Ruby?

I have an array of hashes, and I want the unique values and count out of it. I have:

a = [{:key => 2}, {:key => 1}, {:key => 4}, {:key => 1}]

I want see:

a = [{:key => 2}, {:key => 1, :count =>2}, {:key => 4}]

Upvotes: 1

Views: 1978

Answers (4)

Manivannan Jeganathan
Manivannan Jeganathan

Reputation: 513

Try this:

a.each {|h| count = a.count(h); if count > 1; dup_h = h.clone; h.merge!({:count => count}); a.delete(dup_h); end }

Upvotes: 0

CMW
CMW

Reputation: 3144

The most concise way there is (I think) is this:

a.uniq.map{|hsh| c = a.count(hsh); c == 1 || hsh[:count] = c; hsh}

or if you don't want to modify the hashes in a:

a.uniq.map{|hsh| h = hsh.dup; c = a.count(hsh); c == 1 || h[:count] = c; h}

A (marginally) prettier solution that yields a different result is:

a.uniq.group_by{|hsh| a.count(hsh)}
#=> {1=>[{:key=>2}, {:key=>4}], 2=>[{:key=>1}]}

Check out the documentation on Enumerable#count and Enumerable#group_by to learn more of what you can do with those.
Ruby's core is actually quite powerful.

Upvotes: -1

Ben Miller
Ben Miller

Reputation: 1484

Try this:

a = [{:key => 2}, {:key => 1}, {:key => 4}, {:key => 1}]
b = a.clone
a.uniq!
a.inject([]) { |result,h| h[:count]=b.count(h) if b.count(h) > 1 ; result << h; result }

 => [{:key=>2}, {:key=>1, :count=>2}, {:key=>4}]

Upvotes: 2

Frost
Frost

Reputation: 11957

You will just have to iterate over the array and count how many times each key occurs, and then sum it all together by building a new array with the result.

The below code snippet should do it.

a = [{:key => 2}, {:key => 1}, {:key => 4}, {:key => 1}]

counts = Hash.new(0)

a.map do |item|
  counts[item[:key]] += 1
end

a = counts.collect do |key, count|
  if count > 1
    {:key => key, :count => count}
  else
    {:key => key}
  end
end

Upvotes: 1

Related Questions