Karol Galanciak - Ruby on Rails and Ember.js consultant

The Aesthetics of Ruby - Kernel#itself Method

Recently, I’ve had quite a popular problem to solve: count the occurences of the given item in a collection. There are few ways to solve this problem – starting from using Enumerable#inject or Enumerable#each_with_object with an empty hash as an accumulator value and writing a code looking like this:

1
collection.each_with_object({}) { |item, accum| accum[item] = accum[item].to_i + 1 }

through a bit smarter way and taking advantage of the default hash value:

1
collection.each_with_object(Hash.new(0)) { |item, accum| accum[item] = accum[item] + 1 }

All these solutions look quite nice; however, there is one that looks particularly beautiful.

The Aesthetics of Ruby

An interesting way of solving this problem is by using Enumerable#group_by – we can simply group elements by themselves and count the occurences of each item. Here is one way to implement it:

1
collection.group_by { |item| item }.map { |key, value| [key, value.count] }.to_h

However, it doesn’t look that great, especially for Ruby standard. We could do better. Ruby 2.4 adapted a very useful core extension from ActiveSupport: Hash#transform_values. Thanks to this addition, we could rewrite that to the following code:

1
collection.group_by { |item| item }.transform_values(&:count)

Looks much better, but group_by { |item| item } could still be improved. Is there anything in Ruby that could help us in such case?

It turns out there is! One of the additions in Ruby 2.2 was Kernel#itself, which simply returns self. It might sound like an odd idea to introduce such method, but this is exactly something that we need:

1
collection.group_by(&:itself).transform_values(&:count)

This code looks just beautiful.

Wrapping up

Ruby code is known for being particularly pleasant to read and I’m still happy that after several years I still feel immense joy when I discover interesting little things like Kernel#itself which add up to the overall aesthetics of the language.

Comments