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:
Copymodule Enumerable def count_by(&block) list = group_by(&block) .map { |key, items| [key, items.count] } .sort_by(&:last) Hash[list] end end # Returns a Hash of { key => count } pairs (see below)
Usage examples
- Number of email addresses by domain:
Copy> User.all.count_by { |user| user.email.sub /^.*@/, '' } => { "sina.cn"=>2, ..., "hotmail.com"=>128, "gmail.com"=>153}
- 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:
Copylist .group_by { |item| item.id } # Group .map { |key, items| [key, items.count] } # Count .select { |key, count| count > 10 } # Filter .sort_by(&:last) # Sort ASC .reverse # 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.
makandra has been working exclusively with Ruby on Rails since 2007. Our laser focus on a single technology has made us a leader in this space.