同じ年月は同じグループとしてカウントして数を求める例でのコード比較をRubyでも

はじめに
同じ年月は同じグループとしてカウントして数を求める例でのコード比較を Squeak Smalltalk でも - Smalltalkのtは小文字です経由でこんな問題を見つけたのでRubyでやってみました。

各言語共通ロジック条件

  • 同じ年月は同じグループとしてカウントして数を求める
  • 最新の年月を降順でソートする
  • 無理やり1行にまとめず、ある程度の可読性は保つようにする
  • 宣言部分、実装メソッドの定義部分などはカウントせず除外する
  • //---(logic)----で囲んだ箇所を比較対象箇所とする
  • 下記「変更前」データーから「変更後」データになるよう標準出力を行う
変換前 変換後(降順) 件数
2009-11 2010-12 3
2009-01 2010-04 2
2010-01 2010-01 3
2010-12 2009-11 1
2010-01 2009-01 1
2010-04
2010-01
2010-12
2010-12
2010-04

Scala、Java、PHPでソースコードの量を比較してみる | 深追い Fukaoi.org


コード
コードはこちら。1行だけど可読性は大丈夫なんじゃないかと。

year_months = ['2009-11', '2009-01', '2010-01', '2010-12', '2010-01',
               '2010-04', '2010-01', '2010-12', '2010-12', '2010-04']
 
# ------(logic)--------------------
year_months.group_by { |ym| ym }.sort.reverse.each { |k, v| puts "#{k} => #{v.size}" }
# ------(logic)--------------------


結果はこんな感じ。

2010-12 => 3
2010-04 => 2
2010-01 => 3
2009-11 => 1
2009-01 => 1


Rubyにもgroup_byってあるのね
Enumerableのインスタンスメソッドだそうです。知りませんでした。
instance method Enumerable#group_by - Ruby 1.9.2 Reference Manual
ブロックを評価した結果をキー、対応する要素の配列を値とするハッシュが返ってきます。

[1, 1, 2, 3].group_by { |x| x } #=> {1=>[1, 1], 2=>[2], 3=>[3]} 
(1..10).group_by { |x| x % 2 == 0 } #=> {false=>[1, 3, 5, 7, 9], true=>[2, 4, 6, 8, 10]} 


まとめ
group_byけっこう便利かもしれない。