Ruby: Kernel#itselfの美学(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Ruby: Kernel#itselfの美学(翻訳)

最近私は、Rubyでよくある問題を解決しました。コレクションで渡される項目ごとの頻度をカウントするという問題です。この問題の解決方法はいくつか考えられます。最初は以下のようにEnumerable#injectまたはEnumerable#each_with_objectを用い、空のハッシュをアキュムレータの値として使いました。

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

ハッシュのデフォルト値を用いて、もう少しスマートな方法に変えました。

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

これはこれでなかなかいいのですが、これよりずっと美しい方法があります。

Rubyの美学

この問題を解決する興味深い方法のひとつは、Enumerable#group_byを使う方法です。単に要素をそれら自身でグループ化し、各項目の頻度をカウントします。以下は実装方法の1つです。

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

しかしながら、特にRubyの標準から見てもう少し何とかできそうな気がします。そしてもっといい方法に気づきました。Ruby 2.4ではActiveSupportのcore extensionの非常に便利なHash#transform_valuesが採り入れられました。これを応用すれば、次のように書き換えることができます。

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

ずいぶんよくなりましたが、group_by { |item| item }のあたりをもう少し何とかできそうです。こういう場合に便利な道具がRubyにあるでしょうか?

そう、あるのです!Ruby 2.2で導入されたKernel#itselfは、単にそれ自身を返します。これを使うというアイデアは一見奇妙に思われるかもしれませんが、これがどんぴしゃりはまるのです。

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

コードがここまで美しくなりました。

まとめ

Rubyコードは気持ちよく読めることで特に知られています。そして私はRubyとこれほど長い間付き合っていても、Kernel#itselfのようにRubyという言語にトータルな美しさを付け加えるささやかなものを発見するたびに、言い知れない喜びに浸ります。

その後

関連記事

Rubyのシンボルをなくせるか考えてみた(翻訳)

Rubyのクラスメソッドをclass << selfで定義している理由(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ