今回は並べ替え、つまりソートを行ってみましょう。ソート処理はあちこちで使われます。学校なら成績順やあいうえお順、会社なら商品別の売上順や商品番号、ID順などいろいろあります。
プログラムの世界だとソートはアルゴリズムが話題にされる事があります。ソートのアルゴリズムはプログラマにとっては格好のネタなので検索すると色々な方法があるのがわかります。興味ある方は実際に作ってみると面白いかもしれません。
とは言え自動的にデータを取得し、ソートしてリアルタイムにグラフを生成してモニタに表示するなど、用途によってはsortコマンドを利用した方が便利な時もあるかもしれません。sortコマンドはUNIX系OSだけでなくWindowsにもありますが、今回はUNIX系のsortコマンドについて説明します。
今回もこれまでのようにサンプルで利用するファイル・ディレクトリはデスクトップのsampleディレクトリとしています。デスクトップにsampleディレクトリがない場合は作成しておいてください。(コマンド入力ならmkdir ~/Desktop/sampleとして作成することができます)
また、カレントディレクトリも上記の場所になります。cd ~/Desktop/sampleのようにコマンドを入力してカレントディレクトリを変更しておけばよいでしょう。
整数値をソート
まずは簡単なところで整数値を昇順にソートしてみましょう。ここでは、以下のようなデータを用意しました。1から9までの重複のないデータです。数値は一行に1つで数値の後には改行が入っています。
1.txt
6
4
9
2
8
5
1
3
7
このファイルはデスクトップ上にあるsampleディレクトリ内に1.txtという名前になっています。コマンドで内容を確認する場合はcatコマンドやlessコマンドを使います。
cat 1.txt
内容を確認したら昇順にソートしてみましょう。以下のようにコマンドを入力します。
sort 1.txt
すると一応期待通りの結果にソートされています。今度は逆順、つまり降順にソートしてみましょう。降順にソートするにはrオプションを指定します。reverseの頭文字rなので覚えやすいでしょう。
sort -r 1.txt
ここでも一応期待通りの結果になっています。先ほどの結果も今回の結果も一応と書いたのには理由があります。
今度は以下のように少し(2ヶ所)だけ変えたファイル(2.txt)を用意します。
2.txt
16
4
9
12
8
5
1
3
7
先ほどと同様にsortコマンドを実行してみます。すると以下のように期待とは違う結果になってしまいます。
sort 2.txt
どうしてこうなってしまったのかというと数値のソートではなく文字コード順でソートされてしまったためです。sortコマンドはオプションを指定しないと文字コード順でソートしてしまいます。
数値としてソートするにはnオプションを指定します。つまり、数値としてソートしたい場合は以下のようにします。
sort -n 2.txt
小数値をソート
今度は期待通りの結果になりました。数値と言っても整数値だけのソートでは温度など小数値を含む場合に役立ちません。そこで、先ほどの数値を少し変更して小数値を含むデータを用意してソートしてみましょう。用意したデータファイルは3.txtというファイル名とします。
3.txt
1.6
1.4
9
1.25
0.8
1.05
1
3
7
先ほどと同様にnオプションを指定してソートさせてみましょう。
sort -n 3.txt
小数値を含む場合でも正しくソートされています。とは言え、いずれも正数なので負数を含めてソートできるかもやってみましょう。
今度は負数を含めた以下のようなデータを用意し4.txtというファイル名で保存しておきます。
4.txt
-0.8
1
1.05
-1.25
1.4
1.6
3
7
-9
sortコマンドを使ってソートした結果は以下のようになります。負数でも期待通りにソートされています。さすがに複素数はソートできませんが、通常の用途では問題ないでしょう。
sort -n 4.txt
ソートした結果をファイルに保存するにはリダイレクトを使います。以下のようにするとカレントディレクトリにresult.txtという名前でソートした結果が保存されます。
sort -n 4.txt > result.txt
複数カラムがあるデータをソート
それでは次に複数カラムがあるデータをソートしてみましょう。一般的なデータは1行に複数のデータが記述されている(複数カラム)場合が多いでしょう。
今度は以下のように3列(3カラム)のデータを用意しました。各データは,(カンマ・コンマ)区切りです。CSV形式という名前の方が一般的かもしれません。このファイルをカレントディレクトリに5.txtという名前で用意しておきます。なお、CSV形式の場合は拡張子がcsvという場合もありますが、拡張子の違いでsortコマンドの実行結果は異なることはありません。
5.txt
1,Unix,53
5,CP/M,50
7,TRON,38
4,MS-DOS,41
3,Macintosh,38
2,Windows,37
6,OS/2,35
8,Human68K,36
9,iOS,15
10,AndroidOS,14
これまでのデータとは異なり区切り記号があるのでtオプションで区切り文字を指定する必要があります。sort -t ','のように指定します。
sort -t ',' -n 5.txt
最初のカラムでソートする場合は、これでもよいかもしれませんが、他のカラムでソートする場合は、どうしたらいいのでしょう。この場合はkオプションを使ってソート対象にするカラム番号を指定します。最初のカラムが1、次が2、その次が3という番号になります。以下のようにすると2番目の内容をソートします。この場合、英文字の文字コード順にソートされます。
sort -t ',' -k 2 5.txt
文字コード順でソートされては困る場合は以下のように数値の後にnをつけます。
sort -t ',' -k 3n 5.txt
逆順・降順に並び替える
これまでは昇順にソートしましたが、場合によっては逆順・降順にソートしたい場合もあります。逆順にソートするには-rを指定します。
まずは、最初に使った1.txtファイルを逆順にソートしてみましょう。
sort -r 1.txt
期待通りの結果になっています。それは今度は先ほど使用した5.txtのCSVデータの最初のカラムを逆順にソートしてみます。
sort -r -t ',' -n 5.txt
期待通りの結果になっています。今度は2カラム目を逆順にソートしてみましょう。
sort -r -t ',' -k 2 5.txt
これも期待通りの結果になっています。
ところで、すでにソートされている場合は再びソートする必要はありません。sortコマンドはすでにソート済みなのかどうかを調べることができます。これはcオプションを指定するとソート済みかどうかがわかります。すでにソート済みの場合は何も表示されませんが、未ソートの場合はメッセージが表示されます。
例えば先ほど使用した4.txtはソートされていませんが、ソート結果を保存したresult.txtはソート済みです。それぞれsort
-cとすると以下のようになります。
日本語のソート
最後に日本語でのソートを行ってみましょう。といっても文字コード順にソートされるだけなので、特に特殊なオプションはなく、これまでと変わりません。ただ、現実的にあいうえお順で名前などをソートする場合は気をつけないといけない点もあります。人名・地名など漢字が含まれるものをソートするのであれば、必ず読み仮名を用意しておくということです。漢字だけでは文字コード順にソートされるだけなので期待する結果にならないことがあります。もっともこれはソート以前の問題なのですが、ここらへんは経験者の方が何が必要なのかを知っている分だけよいのかもしれません。
ということで以下のような成績データをソートしてみましょう。これもカンマ区切りデータ、つまりCSV形式になっています。ここでは頑張って先生が入力したデータということで、若干重複した行もあります。疲れていると、こういうコピー&ペーストなどのミスもあります。データのカラムは「ID」「名字」「読み仮名」「算数の点数」「成績ランク」となっています。
6.txt
1,青柳,あおやぎ,56,B
2,佐藤,さとう,78,B
3,中橋,なかはし,38,C
4,高橋,たかはし,68,B
4,高橋,たかはし,68,B
5,山田,やまだ,100,A
6,宮本,みやもと,56,B
7,中田,なかた,96,A
8,山田,やまだ,98,A
8,山田,やまだ,98,A
9,阿佐ヶ谷,あさがや,15,D
10,飯田,いいだ,0,D
11,佐藤,さとう,22,D
12,加藤,かとう,85,A
まず、算数の点数をキーにしてソートしてみましょう。点数の多い順にソートするので逆順にする必要があります。ただし、以下のように指定してしまうと逆順になりません。
sort -t ',' -r -k 4n 6.txt
この場合4nの後にrを付けます。つまり、以下のようなコマンドを入力すれば期待通りの結果になります。
sort -t ',' -r -k 4nr 6.txt
期待通り・・・ではなく重複行が残ってしまっています。これを何とかしなければいけません。重複行をなくすにはいくつかの方法があります。もっとも簡単なのはuオプションを指定することです。以下のようにすると重複行をなくすことができます。
sort -t ',' -r -k 4nr -u 6.txt
とは言えuオプションは場合によっては期待どおりにならないことがあります。そこで重複行をなくすためにuniqコマンドを使う方法もあります。これは以下のようにパイプを使います。
sort -t ',' -r -k 4nr 6.txt|uniq
先ほどあった重複行がなくなっています。
それでは最後にあいうえお順にソートしてみましょう。以下はmacOS(13.2.1)での実行結果です。
sort -t ',' -k 3 6.txt|uniq
困りました。まったく期待通りの結果になっていません。日本語ソートは、なかなかの鬼門ですが、macOSであいうえお順にソートするには以下のようにsortコマンドの前にLC_ALL=Cを付けてから実行します。これで期待通りの結果になります。(今回のデータでは)
LC_ALL=C sort -t ',' -k 3 6.txt|uniq
次にRaspberry Pi OSで実行してみましょう。なお、sortのバージョンは以下のようになっています。
Raspberry Pi OSの場合、以下のようにコマンドを入力するとソートするとあいうえお順になります。
sort -t ',' -k 3 6.txt|uniq
macOS同様にLC_ALL=Cを付けても動作します。が、付けなくても動作するので逆に付けないほうがよいのではないかと思います。localeコマンドを実行するとロケール設定が表示されますが、macOSの方はデフォルトでは何も設定されていないようです。RaspberryPi OSと同様にja_JP.UTF-8を設定してもうまくいかなかったので(ja_JP.EUCなら動く)、とりあえず動くLC_ALL=Cを指定しておくのが妥当なのかもしれません。日本語まわりはなかなか難儀なので泥沼にはまる前に他の方法を考えておくのもありかと思います。
LC_ALL=C sort -t ',' -k 3 6.txt
最後に重複行があるのでuniqコマンドでなくせば出来上がりです。
LC_ALL=C sort -t ',' -k 3 6.txt|uniq
巨大なデータをソートするような場合はsortコマンドではなくデータベースに入れて、そこでソートさせた結果を取得する方法もあります。また、プログラムを作成して処理するのもいいでしょうし、最初に書いたようにエクセルなどを使ってソートしてもよいでしょう。大昔と違ってソートの選択肢はたくさんあります。適材適所、自分が使いやすい方法を使えばよいでしょう。
著者 仲村次郎
いろいろな事に手を出してみたものの結局身につかず、とりあえず目的の事ができればいいんじゃないかみたいな感じで生きております。