Read more

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

Dominik Schöler
August 22, 2017Software engineer at makandra GmbH

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:

module Enumerable
  def count_by(&block)
    list = group_by(&block)
      .map { |key, items| [key, items.count] }

# Returns a Hash of { key => count } pairs (see below)
Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show snapshot

Just paste that snippet into a Rails console and use #count_by now!

Usage examples

  • Number of email addresses by domain:
> User.all.count_by { |user| /^.*@/, '' }
=> { ""=>2, ..., ""=>128, ""=>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: 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:

  .group_by { |item| }                                # 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.

Posted by Dominik Schöler to makandra dev (2017-08-22 14:08)