sort
メソッドによる並べ換えソート(並べ換えること)は、大量のデータ処理には欠かせない。
sort
メソッドの色々な利用方法に慣れておこう。
以下の説明では分かりやすくするため、ソート対象となる配列(またはハッ シュ)に初期値を代入しているが、実践プログラムではプログラム起動時に 入力されたデータなどを元にその都度変わる。
たくさんの値が要素として配列に格納されている場合、それらを
昇順にソートしたものを得たいならたんにsort
メソッドを
呼ぶだけでよい。
x = [9, 20, 10, 15, 8] y = x.sort y => [8, 9, 10, 15, 20] x = ["orange", "apple", "strawberry", "pear"] y = x.sort y => ["apple", "orange", "pear", "strawberry"]
数値でも文字列でも昇順に並べ換えられる。降順にしたい場合は ソート規準を決めるブロックを付加する。
x = [9, 20, 10, 15, 8] y = x.sort{|a, b| b<=>a} y => [20, 15, 10, 9, 8] foo = ["orange", "apple", "strawberry", "pear"] bar = foo.sort{|xx, yy| yy<=>xx} bar => ["strawberry", "pear", "orange", "apple"]
上記の
{|a, b| b<=>a}
という部分が「ソート規準ブロック」であり、この意味は
|a, b| |
2つのものを比べるぞ。左側のものをaとする。 右側にあるものをbとする。 |
b<=>a |
<=> は天秤だ。bを左、aを右に載せるぞ。
左の皿にある方が軽かったら(小さかったら)a, bの順番はそのまま。
右の皿にある方が軽かったら a, b の順番を入れ換えるべし。 |
この規準に則ると、天秤で比べた左の皿にある(b)の方が小さくなる ように並べ換えるので、結果として元の並びの右側の方が小さくなるように、 つまり降順に並べ換えられることになる。
ちなみに、昇順ソートはソート規準ブロックに
{|a, b| a<=>b}
を指定したのと同じである。
x = [9, 20, 10, 15, 8]
y = x.sort{|a, b| a<=>b}
y
=> [8, 9, 10, 15, 20]
これは素直に左の皿に載せた(a)の方が小さくなるように並べ換えられる。
「大きい順」、「小さい順」より複雑な並べ換えもできる。 たとえば、文字列の「最後の1字」の大小で並べ換えてみよう。 そのためには、
両方を理解する必要がある。
ソート規準ブロックに値がどう渡されるか
手作業でものを並べ換えるときでも、基本的には「2つのものの大小を比較」 して、小さい方を左に寄せる、などの作業を積み重ねている。 プログラミング言語でも同様で、どれか2つの値 の大小を比べることの積み重ねで行なっている。
ソート規準ブロック
x.sort {|x, y| ....}
の2つの仮引数が「どれか2つの値」を保持するために使われる。
上記の場合変数 x, y
に配列の要素のどれかが代入される。
文字列の最後の1字の取り出し方
文字列の添字に負の整数を指定すると後から数えた位置の文字を 取り出せる。
"abcdefg"[-1]
=> 103 (103はgの文字コード)
以上のことを踏まえて「文字列の最後の1字の大小でソート」する には以下のようにする。
foo = ["orange", "apple", "strawberry", "pear"]
bar = foo.sort{|xx, yy| xx[-1]<=>yy[-1]}
bar
=> ["orange", "apple", "pear", "strawberry"]
以下のようなハッシュprice
を、値段の安い順に並べ換えたも
のを得たい。
price = { "いちご" => 20, "梨" => 120, "りんご" => 150, "みかん" => 30, }
ハッシュをソートするときには key のみを取り出してそれらを
独自規準でソートするという考え方で進める。Hash
の
もつkeys
メソッドは、ハッシュからkeyのみを
抽出した配列を生成する。
price.keys
=> ["りんご", "いちご", "みかん", "梨"]
key一覧、つまり品名一覧が配列の形で返される(順番はprice
への代入時の順番とは無関係)。これをsort
メソッドで並べ換える。
このとき、並べ換え規準は品名ではなく値段なので、sort
メソッ
ドのソート規準ブロックでは value どうしを比較する。
price.keys.sort {|x, y| price[x] <=> price[y]}
=> ["いちご", "みかん", "梨", "りんご"]
得られた配列は、値段の小さい順に並んでいるので、この要素を一つずつ取 り出し value とペアにして出力していけばよい。
price = { "りんご" => 150, "みかん" => 30, "いちご" => 20, "梨" => 120 } for item in price.keys.sort{|x, y| price[x] <=> price[y]} printf("%s は %d円です。\n", item, price[item]) end
以下の出力が得られる。
いちご は 20円です。 みかん は 30円です。 梨 は 120円です。 りんご は 150円です。
※発展※ →ハッシュ値をまるごとソート