mmts1007’s diary

プログラミング関連の技術系ブログです。

Ruby Enumerable#group_by を使ってみた

DB から取得したデータを Ruby 上でグルーピングしたくてドキュメントを漁っていたら見つけたので紹介。

経緯

DB に入っている

id task_type_id task_id
1 1 1
2 1 2
3 1 3
4 2 4
5 2 5
6 2 6

こんな感じでデータを

[
  {
    task_type_id: 1,
    task_id: [1, 2, 3]
  },
  {
    task_type_id: 2,
    task_id: [4, 5, 6]
  }
]

こんな感じにタスクの種別に紐付いているタスクの一覧 JSONRuby で作りたかった。 task_type_id でグルーピングされた値が取れれば と思い、繰り返し関係を提供している Enumerable モジュールのドキュメントを漁った。

結果

案の定欲しいメソッドはあった。メソッド名見た瞬間、「これ!」ってなった。

instance method Enumerable#group_by (Ruby 2.2.0)

使い方

# DB から取得したデータ
records = [
  { id: 1, task_type_id: 1, task_id: 1 },
  { id: 2, task_type_id: 1, task_id: 2 },
  { id: 3, task_type_id: 1, task_id: 3 },
  { id: 4, task_type_id: 2, task_id: 4 },
  { id: 5, task_type_id: 2, task_id: 5 },
  { id: 6, task_type_id: 2, task_id: 6 }
]

records.group_by { |record| record[:task_type_id] }
# => {1=>[{:id=>1, :task_type_id=>1, :task_id=>1}, {:id=>2, :task_type_id=>1, :task_id=>2}, {:id=>3, :task_type_id=>1, :task_id=>3}], 2=>[{:id=>4, :task_type_id=>2, :task_id=>4}, {:id=>5, :task_type_id=>2, :task_id=>5}, {:id=>6, :task_type_id=>2, :task_id=>6}]}

ということで、task_type_id でグルーピングされた値を取得することができた。
後はデータの形式を求めている形に変換すれば完了

records.group_by { |record| record[:task_type_id] }
  .map { |k, v| { task_type_id: k, task_id: v.map { |e| e[:id] } } }

(group_by の後の map が分かりづらい気がする…。また考えよう。)