Posted 5 months ago. Visible to the public.

Custom Ruby method Enumerable#count_by (use for quick statistics)

I frequently find myself needing a combination of group_by, count and sort for quick statistics. Here's a method on Enumerable that combines the three:

Copy
module Enumerable def count_by(&block) list = group_by(&block) .map{ |key, items| [key, items.count] } .sort_by(&:last) Hash[list] end end

The new method returns a Hash of key => count pairs.

Usage examples

Number of email addresses by domain:

Copy
> User.all.count_by { |user| user.email.sub /^.*@/, '' } => { "sina.cn"=>2, ..., "yahoo.cn"=>63, "hotmail.com"=>128, "gmail.com"=>153}

Others:

  • Number of new users per day: User.all.count_by { |user| user.created_at.to_date }
  • Number of articles per brand: Article.all.count_by &:brand

Note that the last simple example can also be achieved with Rails internals: Article.group(:brand).count. This translates to SQL, so it executes fast. However, grouping is restricted to columns (attributes). Using #count_by gives you the full flexibility of Ruby.

More tools

If you need further options, here's a "toolbox" of chainable method invocations:

Copy
list .group_by{ |item| item.id } # Group .map{ |key, items| [key, items.count] } # Count .select{ |key, count| count > 10 } # Filter .sort_by(&:last) # Sort ASC .sort_by{ |key, count| -count } # Sort DESC .each{ |key, count| puts "#{count.to_s.rjust(6)} #{key}" } # Print

Wrap the result in Hash[...] to turn a list-of-pairs into a Hash.

By refactoring problematic code and creating automated tests, makandra can vastly improve the maintainability of your Rails application.

Author of this card:

Avatar
Dominik Schöler
Last edit:
5 months ago
by Dominik Schöler
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Dominik Schöler to makandropedia