Collection.sortがおまじない状態
現場でソースコードを読んでいるときに
Collection.sort
を使っている箇所について何をしているか理解できませんでした。。
っていう記事もあり、
ということで
私なりに理解したことをまとめました。
ソースコードの例
まずは読みやすい例から紹介します。
5つの数字を昇順ソートにするプログラムです。
昇順ソート
ソースコード
package brog;//自分の環境に合わせてください
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class Sorttest1 {
public static void main(String[] args) {
List num_list = new ArrayList<>(Arrays.asList(30,55,20,15,40));
Collections.sort(num_list);
for (int i=0 ; i< num_list.size() ;i++ ) {
System.out.println(num_list.get(i));
}
}
}
出力結果
- 15
- 20
- 30
- 40
- 55
昇順ソートはわかりやすい
このソースコードはわかると思います。
9行目で宣言したリスト(num_list)を
10行目のCollections.sortに
引数として渡してあげると
昇順ソートしてくれるという理解です。
しかーし!
問題は降順ソートする場合です。
一気にわからなくなりました。。
以下、降順ソートのソースコードです
降順ソート
ソースコード
package brog;//自分の環境に合わせてください。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class SortTest2 {
public static void main(String[] args) {
List num_list = new ArrayList<>(Arrays.asList(30,55,20,15,40));
Collections.sort(num_list,new java.util.Comparator(){
@Override
public int compare(Integer i1,Integer i2) {
return i2 - i1;
}
});
for (int i=0 ; i< num_list.size() ;i++ ) {
System.out.println(num_list.get(i));
}
}
}
出力結果
- 55
- 40
- 30
- 20
- 15
全然わからん!
・・・・ボン!
脳内が例外エラーになりました。
疑問がめっちゃわきます。
昇順ソートを降順ソートに変えただけなのに
コードが一気に増えた!
なんか一個インスタンス生成しているし。
疑問点
私が特にわからなかった点はこの3つでした。
- Comparatorってなに?
- Compareメソッドとは?
- Compareでなぜ引き算してるの?
私が理解した範囲で解説していきます。
1.Comparatorってなに?
まず降順ソートのソースコード11行目に登場する
Comparatorとはなんでしょう?
Oracle javaの公式サイト
には以下の記載がありました。
指定されたコンパレータが示す順序に従って、指定されたリストをソートします。リストのすべての要素は、指定されたコンパレータによって「相互に比較可能」でなければいけません。
つまり、Collection.Sortは
Comparator(コンパレータ)の指示に従ってソートしている
ということなのです。
昇順ソートは?
コンパレータに何も渡さない場合は何ソートになるのか、公式サイトにもはっきりとは書いていませんが、
『Comparatorの指示がなければ昇順ソート』
という理解で良いと思います
2.Compareメソッドとは?
そして2つの目の疑問
Compareメソッドとは何か?
その名の通り
Compare(比較)
を担当するメソッドです。
そもそもソートというのは、
マージソート
バブルソート
クイックソート
・・・と
様々なソートがありますが、
どんなソートの仕方であっても
『2つの値を比較して取り替える』
という処理が何回も繰り返されて、
ソートが行われます。
『2つの値を比較する処理』
を担当しているのが
Compareメソッド
なのです。
3.Compareでなぜ引き算してるの?
降順ソートのソースコード11~16行目で
compareメソッドにi1,i2という引数があり
それを引き算してreturnで返していますね。
降順ソートのソースコード11~16行目
Collections.sort(num_list,new java.util.Comparator(){
@Override
public int compare(Integer i1,Integer i2) {
return i2 - i1;
}
});
Comapreメソッドは
隣り合わせの2つの引数を比較した後、
正か負
で判定返す役割を担当しています。
これは仕様なので覚えてもらうしかないのですが
なぜ引き算しているかというと
Collection.sortの仕様として
Comapre2つの値(i1,i2)を渡し返ってきた値が
- 正ならi1とi2を入れ替える
- ゼロ以下なら何もしない
という仕様になっているからです。
なので、降順ソートにしたいので、
i2 - i1
としているわけです
要はなんなの?
色々解説してしまいましたが
あえて1つ言うならば
意識してもらいたいことは一つです
ソートはどんなソートであっても必ず『比較して入れ替える』処理が入っている
ということです。
なので
Compareメソッド(比較メソッド)をオーバーライドすることで
様々な順番に並び替えることが可能
だという事です。
どのようなソートができるか?
先ほど
Compareメソッド(比較メソッド)をオーバーライドすることで様々な順番に並び替えることが可能
といいましたが、
例えばどのようなソートができるのか?
というと、
偶数が昇順で先に表示され、そのあと奇数が昇順で表示される
といった順序も
降順ソートのCompareを箇所を以下のように書き換えるだけで実現ができます。
複雑なソート例
偶数が昇順で先に表示されそのあと奇数が昇順で表示されるソート
Compareの箇所のみ修正
Collections.sort(num_list,new java.util.Comparator(){
@Override
public int compare(Integer i1,Integer i2) {
int result = i1%2 - i2%2;
if(result==0)
{
result = i1-i2;
}
return result;
}
出力結果
- 20
- 30
- 40
- 15
- 55
中級者への道
今回のCompareをオーバーライドしている箇所のようにわけのわからないプログラムソースに出会ったときに必要なのが
疑問を言語化して分解するです。
今回私は混乱してしまったので3つの疑問にわけました。
- Comparatorってなに?
- Compareメソッドとは?
- Compareでなぜ引き算してるの?
これを1つ1つ調べて理解していけば、最終的には理解できるようになります。