Search

検索したいワードを入力してください

2019年02月19日

Rubyで配列要素を並び替えるには?sort関数の使い方

Rubyで配列を並び替えるにはどうすればいいでしょうか?本記事ではArray#sortとArray#sort_byメソッドを紹介します。ブロックを使用することでソート方法のカスタマイズも可能です。さらに、ハッシュにおけるソートの方法についても説明します

配列のソートとは

ソートとは、数値や文字列などのデータの集まりを、ある順番(数値の大きさ、文字列の辞書順)で並び替える操作のことです。

ソートアルゴリズムには、バブルソート、クイックソート、マージソートなどのアルゴリズムがありますが、ほとんどの言語にはソートするメソッドが定義されているので、通常はこれらのアルゴリズムを意識する必要はありません。

Rubyのその他の配列操作に関する記事はこちら
Rubyの配列の要素や配列自体を削除する方法
Rubyの配列から要素を検索する方法
Rubyの配列の要素数を数える方法
Rubyの配列を結合する方法
Rubyの配列を初期化する方法
Rubyで配列要素を追加する方法

Rubyの配列ソートの方法

Rubyでは、配列のソートを、Array#sortやArray#sort_byメソッドを用いて行います。sort_byメソッドにはブロックが必須です。メソッド名の後に"!"をつけると破壊的メソッドとなり、配列そのものを変更します。

sortメソッドを使ったRuby配列ソートの方法

Array#sortメソッドでは、要素が数値の場合は昇順、文字列の場合は辞書順にソートを行います。以下のRubyスクリプトでは、整数(Integerクラス)配列numを昇順に、文字列(Stringクラス)配列fruitsを辞書順にソートしています。

num=[21, 91, 35, 52, 9, 74, 22, 88]
p num.sort
num.sort! #破壊的メソッド
p num

fruits=%w(Apple Banana Pineapple Pear Grape)
p fruits.sort
fruits.sort!
p fruits

実行結果

[9, 21, 22, 35, 52, 74, 88, 91]
[9, 21, 22, 35, 52, 74, 88, 91]
["Apple", "Banana", "Grape", "Pear", "Pineapple"]
["Apple", "Banana", "Grape", "Pear", "Pineapple"]

sort_byメソッドを使ったRubyの配列ソートの方法

Array#sort_byメソッドでは、ブロックを引数に取り、配列の各要素に関する値でソートを行います。以下のRubyスクリプトでは、文字列配列fruitsを、要素の文字数、pの出現回数によってソートしています。

fruits=%w(Apple Banana Pineapple Pear Grape)
p fruits.sort_by{|item|item.length} #(*)
p fruits.sort_by{|item|item.downcase.count("p")}

実行結果

["Pear", "Apple", "Grape", "Banana", "Pineapple"]
["Banana", "Pear", "Grape", "Apple", "Pineapple"]

ブロックを渡してソート方法をカスタマイズする方法

sortメソッドのブロック内で、比較演算子<=>を使用してソートする方法があります。

a<=>bは、aが大きい場合は1、bが大きい場合は-1、等しい場合は0となります。sortメソッドのブロック内で、変数を2つ指定することで、それらの変数は配列のある2要素となり、ブロックの結果が負ならば、2つの要素を交換するという操作を繰り返します。

したがって、前記(*)のsort_byメソッドは以下のようにも記述できます。

p fruits.sort{|a,b|a.length<=>b.length}
#=>["Pear", "Apple", "Grape", "Banana", "Pineapple"]

sortとsort_byでは速度に違いはある?

sort_byは、sortよりブロック式の実行回数は少なくなり、処理は高速となります。これは、sortではソート中に比較を行うたびに、ブロック式が実行され、sort_byではソートの初めに各要素に対して、ブロック式が実行されるためです。

検証コード

以下のRubyスクリプトでは、100万個のランダムな整数からなる配列を、sortとsort_byメソッドのブロックを利用して、ソートにかかる時間の計測を行います(エンジン:ruby、パッチレベル:95で実行)。

nums=(1..1000000).to_a.shuffle
t0=Time.now
nums.sort{|a,b|a<=>b}
puts format"%.3f(s)",(t1=Time.now)-t0 #=> 1.640(s)
nums.sort_by{|i|i}
puts format"%.3f(s)",(t0=Time.now)-t1 #=> 0.836(s)

これから、sortメソッドは、sort_byメソッドの約2倍の時間がかかっていることが分かります。sortのブロック式よりはsort_byを使った方がパフォーマンス、読みやすさともに上がるので、積極的に使っていきましょう。

ハッシュにおけるソート方法

ハッシュにおいても、sort/sort_byメソッドが使用できます。ソート結果は配列(Arrayクラス)で返されます。ブロックなしでsortメソッドを用いた場合は、キーの順番で並び替えられます。

sortメソッドでブロックを使用する場合、添字の0でキー、1で値を表します。sort_byメソッドでは、ブロック内でキーと値を表す変数を指定します。

サンプルコード

以下は、ハッシュfruitsをキーの辞書順、値の順、キーの文字数の順でソートするRubyスクリプトです。

fruits={"Apple"=>100,"Banana"=>130,"Pineapple"=>158,"Pear"=>124,"Grape"=>138}

#キーについてソート
p (fruits_sorted=fruits.sort)
p fruits_sorted.class

#値についてソート
p fruits.sort{|a,b|a[1]<=>b[1]}
p fruits.sort_by{|k,v|v}

#キーの文字数についてソート
p fruits.sort{|a,b|a[0].length<=>b[0].length}
p fruits.sort_by{|k,v|k.length}

実行結果

[["Apple", 100], ["Banana", 130], ["Grape", 138], ["Pear", 124], ["Pineapple", 158]]
Array
[["Apple", 100], ["Pear", 124], ["Banana", 130], ["Grape", 138], ["Pineapple", 158]]
[["Apple", 100], ["Pear", 124], ["Banana", 130], ["Grape", 138], ["Pineapple", 158]]
[["Pear", 124], ["Apple", 100], ["Grape", 138], ["Banana", 130], ["Pineapple", 158]]
[["Pear", 124], ["Apple", 100], ["Grape", 138], ["Banana", 130], ["Pineapple", 158]]

Rubyで配列を降順にソートする方法

これまで紹介したRubyスクリプトでは、すべて配列を昇順にソートしてきました。では逆に降順にソートするにはどのようにしたらいいのでしょうか?これには、以下の2つの方法があります。

(1)ソートした後にreverseメソッドで逆順にする
(2)sort/sort_byメソッドのブロック内で正負を入れ替える

Rubyのreverseメソッドを使った降順ソートの方法

Rubyの配列(Arrayクラス)には、配列を逆順に並べ替えるreverseメソッドが定義されています。昇順にソートした結果を逆順にすることで、降順にソートした配列が得られます。以下のRubyスクリプトでは、reverseメソッドを用いて、配列fruitsを降順にソートしています。

fruits=%w(Apple Banana Pineapple Pear Grape)
p fruits.sort.reverse
p fruits.sort{|a,b|a.length<=>b.length}.reverse
p fruits.sort_by{|i|i.length}.reverse

実行結果

["Pineapple", "Pear", "Grape", "Banana", "Apple"]
["Pineapple", "Banana", "Grape", "Apple", "Pear"]
["Pineapple", "Banana", "Grape", "Apple", "Pear"]

Rubyのsort/sort_byメソッドを使って配列を降順ソートする方法

sortメソッドのブロック内の比較演算子の左右を交換し、右の要素の方が大きいときに要素を入れ替えるようにします。

比較対象が数値である場合には、sort_byメソッドのブロック内を負の値にすると、大小が逆転するので、ソート結果は降順になります。文字列を辞書の降順にソートする場合には、sort_byメソッドによる方法は使えません。

以下のRubyスクリプトでは、sort/sort_byメソッドを用いて、配列fruitsを降順にソートしています。

fruits=%w(Apple Banana Pineapple Pear Grape)
p fruits.sort{|a,b|b<=>a}
p fruits.sort{|a,b|b.length<=>a.length}
p fruits.sort_by{|i|-i.length}

実行結果

["Pineapple", "Pear", "Grape", "Banana", "Apple"]
["Pineapple", "Banana", "Apple", "Grape", "Pear"]
["Pineapple", "Banana", "Apple", "Grape", "Pear"]

Rubyのto_hメソッドでソート結果をハッシュにする

Rubyには、キーと値の組を要素とする配列をハッシュに変換するArray#to_hというメソッドがあります。逆に、ハッシュを配列に変換するメソッドはHash#to_aです。

ハッシュには、ブロック内では、キーと値の組を要素とする配列([[k1,v1],[k2,v2]...])とみなして扱えるという特徴があり、この逆も可能です。よって、ブロック内で用いるときにはこれらのメソッドを使う必要はありません。

サンプルコード

以下のRubyスクリプトでは、ハッシュfruitsの値によるソート結果をハッシュに変換して出力してます。

fruits={"Apple"=>100,"Banana"=>130,"Pineapple"=>158,"Pear"=>124,"Grape"=>138}
p fruits_sorted=fruits.sort_by{|k,v|v}.to_h
p fruits==fruits_sorted
p fruits.to_a==fruits_sorted.to_a

実行結果

{"Apple"=>100, "Pear"=>124, "Banana"=>130, "Grape"=>138, "Pineapple"=>158}
true
false

Rubyのハッシュは、順番によらず、内容が一致していれば同一オブジェクトと扱われます。よって、ハッシュをソートした後でも、元のハッシュと比較した結果はtrueとなります。

一方、to_aメソッドでは、ハッシュを元の順番のまま配列に変換するので、配列として比較した結果はfalseとなります。

sortとsort_byメソッドの違いに注意しよう

Rubyにおけるsort/sort_byメソッドの違いを表にまとめると、以下のようになります。特にsortとsort_byメソッドにおけるブロックの使い方を混同しないように注意しましょう。

sortsort_by
ブロックなし数値:昇順、文字列:辞書順
ブロックあり2つの要素を比較してソート、低速各要素をブロック式で変換してからソート、高速

これらのメソッドはハッシュ(Hashクラス)でも用いることができます。どちらもソートの結果はキーと値の組を要素とする配列(Arrayクラス)です。

ブロックなしでsortメソッドを用いた場合は、キーについてソートされます。Rubyにおいては、ハッシュと、キーと値の組を要素とする配列は、相互変換しなくても、ブロック内では同じように扱えます。

Rubyのその他の配列操作に関する記事はこちら
Rubyの配列の要素や配列自体を削除する方法
Rubyの配列から要素を検索する方法
Rubyの配列の要素数を数える方法
Rubyの配列を結合する方法
Rubyの配列を初期化する方法
Rubyで配列要素を追加する方法

【PR】多くの人がプログラミングを諦めてしまう理由をご存知ですか?



近年プログラミングを勉強する人が増えています。

プログラミング学習者の多くは独学から取り組もうとしますが、だいたい80%ほどは3ヶ月も続かずに諦めてしまいます。早い人は1日目で。

多くの人がプログラミングを独学しようとして諦める理由は、次の3つ。
●モチベーションが維持できない
●エラーの原因・解決方法が分からない
●どう学習すればよいか分からない

TechBoostというプログラミングスクールでは、みんなと一緒にプログラミングをするのでモチベーションの維持ができ、分からないことがあればマンツーマンで教えてくれ、徹底的に研究された初心者向けの教材が揃っています。

TechBoostを卒業後、実際にエンジニアとして転職した方もいるほど。

本気でプログラミングを学びたい方は、一度無料のカウンセリングでご相談ください。プログラミングを嫌いになる前に。

tech boostについて

オーダーメイド型の学習コンテンツを提供する「tech boost」 は、エンジニアのキャリア支援に特化したサービスを複数展開している株式会社Branding Engineerが運営しているプログラミングスクールです。最短3ヶ月間で、未経験から『プログラミングの基礎』、『実際に業務で必要となるスキル』、『今のトレンドとなっている知識』まで学べ、ご希望の方にはプロのキャリアアドバイザーによる就業支援を行うことができます。

tech boost卒業生インタビュー

tech boostの卒業生の声を聞きました。あなたがプログラミングを学びたい理由を、一度考えてみてください。
営業→Javaエンジニア→Rubyエンジニアと転向し、第一志望のFinTech企業で働く山下さん
元営業、ビジネスのわかるエンジニアを目指す菅原さん
サンフランシスコに交換留学し、シリコンバレーのVCでインターン中の梅本さん
予備校の営業から半年でエンジニア転職を果たした小田島さん

tech boostの口コミ



Related