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] }
.sort_by(&:last)
Hash[list]
end
end
# Returns a Hash of { key => count } pairs (see below)
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| 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:
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
.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 12:08)