【Java】Listのソート方法
Collections クラス
Collections
クラスは、List
やMap
に関連するstatic
なメソッドが定義されています。
その中の 1 つにsort()
があります。
sort()
はオーバーロードされていて、Comparable
を使うものとComparator
を使うものの 2 種類があります。
Comparable によるソート
以下はInteger
とString
のソート方法の例になります。
Integer[] nums = {10, 4, 6, 2, 8};
List<Integer> list = Arrays.asList(nums);
//昇順ソート 2, 4, 6, 8, 10
Collections.sort(list);
//降順ソート 10, 8, 6, 4, 2
Collections.sort(list, Collections.reverseOrder());
String[] strs = {"ABC", "abc", "123", "1A", "A12"};
List<String> list = Arrays.asList(strs);
//昇順ソート 123, 1A, A12, ABC, abc
Collections.sort(list);
//降順ソート abc, ABC, A12, 1A, 123
Collections.sort(list, Collections.reverseOrder());
どちらもsort()
の引数にList
を渡すだけでソートされていることがわかります。
では、自作したクラスではどうでしょうか。
public class MyClass {
private int num;
private String str;
//Constructor
public MyClass(int num, String str) {
this.num = num;
this.str = str;
}
}
List<MyClass> list = new ArrayList<>();
list.add(new MyClass(1, "ABC"));
list.add(new MyClass(2, "ABC"));
list.add(new MyClass(1, "BAC"));
list.add(new MyClass(0, "CCC"));
list.add(new MyClass(2, "000"));
//昇順ソート
Collections.sort(list);
//降順ソート
Collections.sort(list, Collections.reverseOrder());
これだけではソートは実行されません。なぜならどのようにソートをすれば良いかがわからないからです。
これを定義するのがComparable
になります。
public class MyClass implements Comparable<MyClass> {
//省略
@Override
public int compareTo(MyClass another) {
int cmp = 0;
//numを比較する
if ((cmp = this.num - another.num) != 0) {
return cmp;
}
//numの値が同じ場合はstrを比較する
return this.str.compareTo(another.str);
}
}
自作クラスをソートしたい場合は、インターフェースであるCompareble
のcompareTo()
を実装します。
compareTo()
は、自身と引数を比較した時に、大きければ正の値、小さければ負の値、同じであれば 0 になるように実装します。
これによってsort()
は、並び替えの条件を判断しています。
上の例の昇順ソートは下記のようになります。
{ num: 0, str: "CCC" },
{ num: 1, str: "ABC" },
{ num: 1, str: "BAC" },
{ num: 2, str: "000" },
{ num: 2, str: "ABC" },
Integer
とString
にはあらかじめComparable
が実装されているためソートが実行されていました。
Comparator によるソート
Comparator
によるソートは、Comparable
で定義したものとは違うルールでソートしたい場合に使用します。
例えば、先程のMyClass
のソートをnum
, str
の順ではなく、str
, num
の順でソートしたいとします。
List<MyClass> list = new ArrayList<>();
list.add(new MyClass(1, "ABC"));
list.add(new MyClass(2, "ABC"));
list.add(new MyClass(1, "BAC"));
list.add(new MyClass(0, "CCC"));
list.add(new MyClass(2, "000"));
//ソートの定義
Comparator comparator = new Comparator<MyClass>() {
@Override
public int compare(MyClass a, MyClass b) {
int cmp = 0;
if ((cmp = a.str.compareTo(b.str)) != 0) {
return cmp;
}
return a.num - b.num;
}
}
//昇順ソート
Collections.sort(list, comparator);
//降順ソート
Collections.sort(list, comparator.reversed());
例のように無名クラスとしてComparator
のcompare()
を実装します。
compare()
の実装は、Comparable
のcompareTo()
を同じ考え方です。
これによって昇順ソートは下記のようになります。
{ num: 2, str: "000" },
{ num: 1, str: "ABC" },
{ num: 2, str: "ABC" },
{ num: 1, str: "BAC" },
{ num: 0, str: "CCC" },