概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: The aesthetics of Ruby - Kernel#itself method
- 原文公開日: 2017/12/26
- 著者: Karol Galanciak
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という言語にトータルな美しさを付け加えるささやかなものを発見するたびに、言い知れない喜びに浸ります。
その後
この記事を読んで不思議で不思議でならないのは、なぜ元記事を書いた人は入力値と出力値の例を1つも載せなかったということだ。このコードだけ見て何がどうなるか完璧に予想できる人はそんなに多くないだろうに(僕でも自信がなかった)。
Ruby: Kernel#itselfの美学(翻訳) https://t.co/pH1NAWEwxV pic.twitter.com/LsMHc2u8FK— Junichi Ito (伊藤淳一) (@jnchito) January 23, 2018