Ruby’s tally method was introduced in 2.7. It’s a super convenient method on Enumerable that I was recently able to use. Tally counts each element’s occurrences and returns a hash where the key is the element, and the value is the count.

Pre-Tally

If you are like me, any time you needed to get back a count of the times an element showed up in a collection, you headed over to StackOverflow and looked up how to do it. You probably ended up implementing something that looked like one of the examples below:

list = ["a", "b", "b", "a", "c", "d", "d", "d", "e"]

list.group_by { |v| v }.map { |k, v| [k, v.size] }.to_h
#=> {"a"=>2, "b"=>2, "c"=>1, "d"=>3, "e"=>1}

list.each_with_object(Hash.new(0)) { |v, h| h[v] += 1 }
#=> {"a"=>2, "b"=>2, "c"=>1, "d"=>3, "e"=>1}

Maybe you needed to count how many times some value showed up in a collection of hashes.

hashes = [{name: "Meagan" }, { name: "Meagan" }, { name: "Lauren" }]

hashes.group_by(&:itself).map { |k, v| k.merge(count: v.length)}
#=> [{ :name => "Meagan", :count => 2}, { :name => "Lauren", :count => 1 }]

Using tally

Tally makes that collection into hash transformation so much easier.

list = ["a", "b", "b", "a", "c", "d", "d", "d", "e"]
list.tally
#=> {"a"=>2, "b"=>2, "c"=>1, "d"=>3, "e"=>1}

Bam. You did it. Let’s use tally on our collection of hashes example.

hashes = [{name: "Meagan" }, { name: "Meagan" }, { name: "Lauren" }]
h.tally
#=> {{:name=>"Meagan"}=>2, {:name=>"Lauren"}=>1}

hashes.tally.map { |k, v| k.merge({count: v}) }
#=> [{:name=>"Meagan", :count=>2}, {:name=>"Lauren", :count=>1}]

It still requires a little bit of munging to get the same return we got in the pre-tally example.

Conclusion & Further Reading

I hope that you found this useful and can add tally to your toolkit. Knowing tally means one less Google search I’ll need to do in the future when I’ve got to count occurrences of an element in an array.