すみません控えのみです。
まずsortメソッド、sort_byメソッドの復習
- instance method
Enumerable#sort
sort -> [object]
sort {|a, b| ... } -> [object]
全ての要素を昇順にソートした配列を生成して返します。
ブロックなしのときは<=>
メソッドを要素に対して呼び、 その結果をもとにソートします。
<=>
以外でソートしたい場合は、ブロックを指定します。 この場合、ブロックの評価結果を元にソートします。 ブロックの値は、a > b
のとき正、a == b
のとき 0、a < b
のとき負の整数を、期待しています。 ブロックが整数以外を返したときは例外TypeError
が発生します。
Enumerable#sort_by
は安定ではありません (unstable sort)。 安定なソートが必要な場合はEnumerable#sort_by
を使って工夫する必要があります。 詳しくはEnumerable#sort_by
の項目を参照してください。
※ 比較結果が同じ要素は元の順序通りに並ぶソートを 「安定なソート (stable sort)」と言います。
[SEE_ALSO]Enumerable#sort_by
http://rurema.clear-code.com/1.9.3/method/Enumerable/i/sort.html
- instance method
Enumerable#sort_by
sort_by -> Enumerator
sort_by {|item| ... } -> [object]
ブロックの評価結果を<=>
メソッドで比較することで、self
を昇順にソートします。ソートされた配列を新たに生成して返します。
つまり、以下とほぼ同じ動作をします。class Array def sort_by self.map {|i| [yield(i), i] }. sort {|a, b| a[0] <=> b[0] }. map {|i| i[1]} end end
Enumerable#sort
と比較してsort_by
が優れている点として、 比較条件が複雑な場合の速度が挙げられます。
Enumerable#sort_by
は安定ではありません (unstable sort)。 ただし、sort_by
を以下のように使うと安定なソートを実装できます。i = 0 ary.sort_by {|v| [v, i += 1] }※ 比較結果が同じ要素は元の順序通りに並ぶソートを 「安定なソート (stable sort)」と言います。
ブロックを省略した場合は、各要素をブロックで評価した値でソートした 配列を返すようなEnumerator
を返します。
[SEE_ALSO]Enumerable#sort
http://rurema.clear-code.com/1.9.3/method/Enumerable/i/sort_by.html
複数キーソート(昇順のみ)
Bookのauthorを第1キー、titleを第2キーとして昇順ソートする。
:books = books.sort_by do |b| [b.author, b.title] end
複数キーソート(昇順・降順混在)
ところが、この方法だと降順でソートするのが難しい。
books.reverse!
で、全体を逆順にすることはできる。
しかし、昇順と降順が混在するようなソートはできない。ブロックつきのsortメソッドを使えば、降順ソートも可能となる。
authorで昇順、titleで降順ソートするコードは下記のようになる。
:books.sort! do |a, b| (a.author <=> b.author).nonzero? || (b.title <=> a.title) end
nonzero?
は、ゼロの時nil
を返し、非ゼロの時self
を返す。
第1キー(author)が同じであれば、第2キー(title)を比較することになる。
The Art of Software : Rubyで複数キーを使ったソートとパフォーマンス
このNumeric#nonzero?
メソッド、いいですね。すっごく便利。
nonzero? -> self | nil
自身がゼロの時nil
を返し、非ゼロの時self
を返します。
http://rurema.clear-code.com/1.9.3/method/Numeric/i/nonzero=3f.html
いま書いてるスクリプトで必要だったのは二項目とも昇順のソートだったので、sort_by
で二項目配列をブロックに入れて比較項目にしました。
昇順・降順が混在するソートを書くときのためのメモ。その場合には、後者のsort
を使います。