views:

487

answers:

6

How do you count duplicates in a ruby array?

For example, if my array had three a's, how could I count that

+4  A: 

This will yield the duplicate elements as a hash with the number of occurences for each duplicate item. Let the code speak:

#!/usr/bin/env ruby

class Array
  # monkey-patched version
  def dup_hash
    inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select { 
      |k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
  end
end

# unmonkeey'd
def dup_hash(ary)
  ary.inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select { 
    |k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
end

p dup_hash([1, 2, "a", "a", 4, "a", 2, 1])
# {"a"=>3, 1=>2, 2=>2}

p [1, 2, "Thanks", "You're welcome", "Thanks", 
  "You're welcome", "Thanks", "You're welcome"].dup_hash
# {"You're welcome"=>3, "Thanks"=>3}
The MYYN
-1 for unnecessary monkey patch.
Bob Aman
thx. answer now includes a non-monkey-patched version.
The MYYN
No longer -1, but seriously... don't monkey patch unless there's just no other way to do it.
Bob Aman
+1  A: 

I don't think there's a built-in method. If all you need is the total count of duplicates, you could take a.length - a.uniq.length. If you're looking for the count of a single particular element, try a.select {|e| e == my_element}.length.

Thom Smith
+2  A: 

Simple.

arr = [2,3,4,3,2,67,2]
repeats = arr.length - arr.uniq.length
puts repeats
JRL
Thanks! This worked well for me. I keep forgetting about uniq ....
CalebHC
+3  A: 

requires 1.8.7+ for group_by

ary = %w{a b c d a e f g a h i b}
ary.group_by{|elem| elem}.select{|key,val| val.length > 1}.map{|key,val| key}
# => ["a", "b"]

with 1.9+ this can be slightly simplified because Hash#select will return a hash.

ary.group_by{|elem| elem}.select{|key,val| val.length > 1}.keys
# => ["a", "b"]
glenn jackman
+2  A: 

Another version of a hash with a key for each element in your array and value for the count of each element

a = [ 1, 2, 3, 3, 4, 3]
h = Hash.new(0)
a.each { | v | h.store(v, h[v]+1) }

# h = { 3=>3, 2=>1, 1=>1, 4=>1 }
Kim
A: 

To count instances of a single element use inject

array.inject(0){|count,elem| elem == value ? count+1 : count}
Chris