ArrayList 要素のソートと Comparator

ArrayList は動的なリストで add メソッドによって、どんどん要素を追加していくことができます。 追加された要素は基本的に追加した順番にリストとして並んでいます。

しかし、これを読み出す時にはある並び順で並んでいて欲しい場合もあるでしょう。

ここでは ArrayList に格納されたオブジェクト要素を、どうやって並べ替えるか、ということについて説明します。

YouTube 解説ビデオ「オブジェクトを並べ替えるとは?コンパレータの実装方法」

オブジェクトのソートとコンパレータの実装方法について、解説ビデオを作成しました。 このページで書いている内容をほぼそのまま説明してます。

このビデオを見ていただければ、すぐわかると思います。

励みになりますので、できればチャンネル登録もお願いします

リスト内の要素の並べ替えとは?

ArrayList というのは何らかの要素 (オブジェクト) が数珠繋ぎに並んでいて、インデックスを使って配列のごとく特定の要素にアクセスできるというコレクションのことです。

今回はこのオブジェクト要素を何らかの条件に従って並び替えたい、ソートしたいという場合のことを考えます。

例えば整数の並び替えならば、大きなものから小さなものへとか、小さなものから大きなものへという風にソートされることは分かりやすいですね。

ですが、例えば「従業員オブジェクト」のリスト要素をソートする、という場合、どういう条件で並べ替えるか自明ではありません。

従業員の年齢でソートするかもしれませんし、名前のあいうえお順で並び替えるかもしれません。

つまり、並べ替えの順番は必ずしも明らかなものばかりではないので、並べ替えのルールも自分で実装する必要があるのです。

並べ替えのルールは Comparator によって実装します。

ArrayList 要素のソート

ここでは一般的に何らかのオブジェクトを要素にするリストを考え、それをソートする場合について説明します。

文字列要素の場合のソート 〜 デフォルトの並べ替え例

まずは、分かりやすい文字の並べ替え (ABC 順) からみてみましょう。

ここでは String を要素とする ArrayList を用意し、それを並び替える方法を示します。

package com.keicode.java.test;

import java.util.ArrayList;
import java.util.Collections;

public class SortTest {
	public static void main(String[] args) {

		ArrayList<String> stateList = new ArrayList<String>();
		stateList.add("TX");
		stateList.add("WA");
		stateList.add("CA");

		for(int i=0;i<stateList.size();i++){
			System.out.println(stateList.get(i));
		}

		Collections.sort(stateList);
		System.out.println("--- Sorted ---");

		for(int i=0;i<stateList.size();i++){
			System.out.println(stateList.get(i));
		}

	}
}

ここではソート前の内容と、ソート後の内容を出力しています。

これの実行例は次の通りです。

TX
WA
CA
--- Sorted ---
CA
TX
WA

ABC 順で並び替えられていますね。

このように自然で自明な並び替えの場合、Collections.sort を呼べばたいていの場合デフォルトのソートで十分間に合います

Collections.sort(...);

この場合、特に並べ替えのルールを自前で実装する必要はありません。

並べ順が自明ではないオブジェクト要素のソート

問題はもう少し複雑なオブジェクトのコレクションの場合です。

前述の通り、それぞれのオブジェクトの並び順などは自明ではないことが多いので、ソート順自体を定義しなければなりません。

Collections.sort は第二パラメータで Comparator オブジェクトを受け取ります。この Comparator というのが、 ソート順のルールを定義するためのクラスです。Comparator によってカスタムのソート順を適用することが可能になります。

Comparator は Comparator<T> インターフェイスを実装したクラスのことです。 Comparator<T> インターフェイスは compare というメソッドを1つ持っているだけの、シンプルなインターフェイスです。

さっそく、具体例です。

次のような Person (人) クラスを定義します。

package com.keicode.java.test;

public class Person {
	public int age;
	public String name;

	public Person(int age, String name){
		this.age = age;
		this.name = name;
	}
}

これを年齢 (age) を元にソートしたいという状況を考えます。

そこで次のような Comparator を定義します。

package com.keicode.java.test;

import java.util.Comparator;

public class PersonComparator implements Comparator<Person> {

	@Override
	public int compare(Person p1, Person p2) {
		return p1.age < p2.age ? -1 : 1;
	}
}

compare メソッドで、負の数、0、正の数 (int) を返すことによって、その大小を定義します。 第一引数を小さいとする場合は負の数。大きいとする場合は正の数を返せば OK です。

このように定義したコンパレータ PersonComparator は、次のように利用します。

package com.keicode.java.test;

import java.util.ArrayList;
import java.util.Collections;

public class SortTest {
	public static void main(String[] args) {

		ArrayList<Person> memberList = new ArrayList<Person>();
		memberList.add(new Person(40, "Hanako"));
		memberList.add(new Person(50, "Taro"));
		memberList.add(new Person(20, "Ichiro"));

		for(int i=0;i<memberList.size();i++){
			System.out.format("%s - %d\n",
				memberList.get(i).name,
				memberList.get(i).age);
		}

		Collections.sort(memberList, new PersonComparator());
		System.out.println("--- Sorted ---");

		for(int i=0;i<memberList.size();i++){
			System.out.format("%s - %d\n",
				memberList.get(i).name,
				memberList.get(i).age);
		}

	}
}

この実行結果は次の通り。

Hanako - 40
Taro - 50
Ichiro - 20
--- Sorted ---
Ichiro - 20
Hanako - 40
Taro - 50

確かに年齢順にソートされていますね。

以上で、オブジェクトをソートする場合の問題点とコンパレータ、そしてコンパレータを実際に使ってオブジェクトをソートする例を紹介しました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Java 入門