sortやsort_byメソッドを使用すると、配列の中身をソート(並び替え)することができます。この記事では、Rubyの配列をソートするsortとsort_byメソッドの使い方を解説します。
sortメソッド
sortメソッドで配列を並び替える方法を見ていきましょう。
配列をソート
最初は、シンプルに数値の配列をソートする例を確認しましょう。
次のように、数値がバラバラに並んだ配列を宣言し、その配列に対しsortメソッドを呼び出すと、配列の中身を昇順で並び替えた新たな配列が戻り値として取得できます。
array = [300, 200, 150, 400, 100]
p array.sort
【実行結果】
[100, 150, 200, 300, 400]
破壊的メソッドで自分自身の配列をソート
メソッド名の末尾にびっくりマークが付くメソッドは、自分自身の値を書き換える破壊的メソッドと呼ばれ、Rubyの言語としての特徴でもあります。
sortメソッドにも破壊的メソッドがあり、sort!を使用すると自分自身の配列を昇順にソートした結果で書き換えます。
array = [300, 200, 150, 400, 100]
puts "--- sort (非破壊メソッド) ---"
array.sort
p array
puts "--- sort! (破壊的メソッド) ---"
array.sort!
p array
【実行結果】
--- sort (非破壊メソッド) ---
[300, 200, 150, 400, 100]
--- sort! (破壊的メソッド) ---
[100, 150, 200, 300, 400]
このように、非破壊メソッドのsortメソッドでは、配列自身の中身は変更されませんが、破壊的メソッドであるsort!を呼び出すと、呼び出し元の配列自身がソートされているのが分かります。
降順に並び替えるには?
Rubyのsortメソッドは昇順でのソートしかできず、配列を降順でソートする直接的なメソッドは存在しません。降順て配列をソートする場合は、昇順で配列をソートするsortメソッドと、要素の中身を反転させるreverseメソッドを組み合わせて降順ソートを実現します。
array = [300, 200, 150, 400, 100]
p array.sort.reverse
【実行結果】
[400, 300, 200, 150, 100]
破壊的メソッドを使用することにより、自身の配列を降順にソートすることも可能です。
array = [300, 200, 150, 400, 100]
array.sort!.reverse!
p array
【実行結果】
[400, 300, 200, 150, 100]
文字列のソート
文字列配列であっても、数値と同様にsortメソッドで並び替えれます。文字列配列の場合は、文字コード順に配列がソートされます。
array = ["C", "Z", "A", "E"]p array.sort
【実行結果】
["A", "C", "E", "Z"]
構造化データを並び替える
配列の中にハッシュやクラスなどの構造化されたデータが格納されている配列をソートする場合は、ソート条件をsortメソッドに指定する必要があります。
次のように、商品名と金額のハッシュが格納された配列を、金額の昇順で並び替えるサンプルコードを見てみましょう。
array = [ {"name" => "うどん", "price" => "300"}, {"name" => "パスタ", "price" => "700"}, {"name" => "ラーメン", "price" => "500"}]p array.sort {|x, y| x["price"] <=> y["price"] }
【実行結果】
[{"name"=>"うどん", "price"=>"300"}, {"name"=>"ラーメン", "price"=>"500"}, {"name"=>"パスタ", "price"=>"700"}]
このように、sortメソッドにブロック指定することで、任意の条件で配列の中身をソートすることができます。
sort_by
次は、sort_byメソッドの使い方を解説していきます。
sortとsort_byメソッドは、どちらも配列をソートするメソッドですが、一般的にはsort_byメソッドの方が処理速度が早いと言われるため、基本的にはsort_byメソッドを使っていった方がよいでしょう。
sort_byメソッドの基本的な使い方
数値の配列を昇順でソートする基本的なサンプルコードです。
sortメソッドでは、数値や文字列などの単純な値の配列の場合、ブロックでソート条件を指定する必要はありませんでしたが、sort_byメソッドではブロックでソートする値を必ず指定します。
array = [300, 200, 150, 400, 100]p array.sort_by {|value| value}
【実行結果】
[100, 150, 200, 300, 400]
構造化データを並び替える
構造化データが格納された配列をソートする場合も、sort_byメソッドのブロックに、昇順で並び替えたい項目を指定することで、配列をソートできます。
array = [ {"name" => "うどん", "price" => "300"}, {"name" => "パスタ", "price" => "700"}, {"name" => "ラーメン", "price" => "500"}]p array.sort_by {|x| x["price"] }
【実行結果】
[{"name"=>"うどん", "price"=>"300"}, {"name"=>"ラーメン", "price"=>"500"}, {"name"=>"パスタ", "price"=>"700"}]
sort_byとsortメソッドの違い
sort_byとsortメソッドの違いには、sort_byの方が処理時間が早くなることが挙げられます。特に、比較条件が複雑で時間がかかるほど、その処理時間の差が顕著に現れます。
次のコードは、Rubyの公式サイトでも紹介されており、sort_byとsortメソッドで比較メソッドの実行回数がどれほど違うのかを検証するサンプルコードです。
class Integer def count $n += 1 self endendary = []1.upto(1000) {|v| ary << rand(v) }$n = 0ary.sort {|a,b| a.count <=> b.count }puts "sort=" + $n.to_s$n = 0ary.sort_by {|v| v.count }puts "sort_by=" + $n.to_s
【実行結果】
sort=16446sort_by=1000
このように、sortメソッドは比較を行う度にcountが呼ばれています。一方で、sort_byメソッドは配列の要素数と同じ数だけしかcountが呼ばれておらず、非常に効率的にソートが行われており、これがsort_byメソッドの方が処理速度が早いと言われている理由です。
配列のソートをマスターしよう
Rubyのsortやsort_byメソッドを使って、配列をソートする方法を紹介してきました。ソート処理はさまざまなシーンで使われますので、是非マスターしておきましょう。
上のサンプルコードで、Ruby特有の比較メソッドの<=>が出てきました。これはself <=> otherのような条件であった場合、selfが大きい時に正、等しい時は0、小さい時に負の整数を返す比較メソッドです。Rubyではこの<=>メソッドを使うことにより、大小比較の条件を非常にシンプルに記述できます。