Here's a small implementation:
class Counter < Hash
def initialize(other = nil)
super(0)
if other.is_a? Array
other.each { |e| self[e] += 1 }
end
if other.is_a? Hash
other.each { |k,v| self[k] = v }
end
if other.is_a? String
other.each_char { |e| self[e] += 1 }
end
end
def +(rhs)
raise TypeError, "cannot add #{rhs.class} to a Counter" if ! rhs.is_a? Counter
result = Counter.new(self)
rhs.each { |k, v| result[k] += v }
result
end
def -(rhs)
raise TypeError, "cannot subtract #{rhs.class} to a Counter" if ! rhs.is_a? Counter
result = Counter.new(self)
rhs.each { |k, v| result[k] -= v }
result
end
def most_common(n = nil)
s = sort_by {|k, v| -v}
return n ? s.take(n) : s
end
def to_s
"Counter(#{super.to_s})"
end
def inspect
to_s
end
end
It supports
- construction from strings, arrays and hashes
- accessing and modifying counts
- addition and substraction for two Counters
- access for the
most_common
element(s)
c1 = Counter.new([1,0,1]) #=> Counter({1=>2, 0=>1})
c1[2] = 1 #=> 1
c1 #=> Counter({1=>2, 0=>1, 2=>1})
c2 = Counter.new([3,1]) #=> Counter({3=>1, 1=>1})
c1 + c2 #=> {1=>3, 0=>1, 2=>1, 3=>1}
c3 = Counter.new("abraca") #=> {"a"=>3, "b"=>1, "r"=>1, "c"=>1}
c3.most_common(2) #=> [["a", 3], ["b", 1]]