お仕事で、以下のようなソートを実装する機会がありました。
例として教科書を題材にします。
Text model
教科書は、教科コード、4種類のとあるタイプと、応用/基礎の情報を持っています。
class Text enum type: { a_type: 'a_type', b_type: 'b_type', c_type: 'c_type', } enum subject: { japanese: 'japanese', math: 'math', english: 'english'} # 基礎/応用はfalse/trueで表現しています ... end
仕様
これから実装するのは以下の仕様です。
- 最初に教科でソートする。
- 同じ教科の中でtypeごとにソート
- それでも一緒なら「基礎/応用」でソートする
例えば、
```
{subject: 'english', type: 'c_type', support_advanced: true},
{subject: 'english', type: 'a_type', support_advanced: true},
{subject: 'english', type: 'b_type', support_advanced: true},
{subject: 'english', type: 'b_type', support_advanced: false},
{subject: 'math', type: 'c_type', support_advanced: true},
{subject: 'japanese', type: 'b_type', support_advanced: false},
{subject: 'english', type: 'c_type', support_advanced: true},
```
みたいなデータがきたら、
```
{subject: 'english', type: 'a_type', support_advanced: true},
{subject: 'english', type: 'b_type', support_advanced: true},
{subject: 'english', type: 'b_type', support_advanced: false},
{subject: 'english', type: 'c_type', support_advanced: true},
{subject: 'english', type: 'c_type', support_advanced: false},
{subject: 'math', type: 'c_type', support_advanced: true},
{subject: 'japanese', type: 'b_type', support_advanced: false},
```
みたいにしたいです。
結論
こうやって書きます。
subjects = %w[english, math, japanese] types = %w[a_type, b_type, c_type] sort_support_advanced = [true, false] texts.sort_by do |text| [ subjects.find_index { |subject| text.subject == subject }, types.find_index { |type| text.type == type }, sort_support_advanced.find_index { |support_advanced| text.support_advanced == support_advanced } ] end
解説
配列の番号で順番を指定できます。
find_indexは条件に一致する最初の要素の位置を返します。
subjects = %w[english, math, japanese] types = %w[a_type, b_type, c_type] sort_support_advanced = [true, false]
そしてsort_by に、配列のindex(位置情報)を渡してあげると、配列で並べた通りに並べ替えてくれます。
texts.sort_by do |text| [subjects.find_index { |subject| text.subject == subject } ] end
ソートした中でさらに別の条件でソートしたい場合、以下のように書くと上から順に並び替えてくれます。
texts.sort_by do |text| [ subjects.find_index { |subject| text.subject == subject }, types.find_index { |type| text.type == type }, sort_support_advanced.find_index { |support_advanced| text.support_advanced == support_advanced } ] end
以上です。