Sort

同種のデータの集まりがあるとき、それをソート(整順)させたいという事は 多いものと思います。アルゴリズムの本には必ずといってよいほど色々な ソートに関して記述されています。 ただJavaでプログラムを作成する場合、自分で何かソートのアルゴリズムを実装 する、というような事はしません(何か特別な理由がある場合は別ですが)。 配列をソートしたいときはjava.util.Arrays、Collectionをソートしたいときは、 java.util.Collectionsのクラスメソッドを使うのが普通です。 例えばStringの配列を昇順にソートしたいのであれば、

	String[] stringArray = getArrayFromAnywhere();
	java.util.Arrays.sort(stringArray);
とするだけです。int[]やchar[]といった配列でも同じようにソートできます。 これらのメソッドはQuick Sortと呼ばれるアルゴリズムが使われています。

では自分で作ったクラスのインスタンスをソートするには、 どうすればよいでしょうか。2つの方法があります。1つはソートしたい オブジェクトのクラスで、java.lang.Comparableインタフェースを implementsする方法、もう一つはソート対象のオブジェクトとは別に java.util.Comparatorをimplementsしたクラスを作成する方法です。

Comparableをimplementsする方法

例えば、名前と年齢からなるPersonというクラスを作成するとしましょう。
	/**
	 * 名前と年齢のクラス。
	 */
	public class Person {
		/** 名前 */
		public String name;
		/** 年齢 >= 0 */
		public int age;
	}
このクラスのインスタンスを年齢順にソートしたい場合、Personで java.lang.Comparableインタフェースをimplementsします。 ComparableインタフェースにはcompareTo()というメソッドがありますので、 これを実装します。compareToの引数は比較対象のObjectで、 自分自身と同じクラス(上記の場合はPerson)のインスタンスであることを 仮定して構いません。 compareTo()の戻り値は、自分の方が小さいときは負の値、同じなら0、 自分の方が大きいなら正の値を返すことになっています。したがってこの場合は、
	/**
	 * 名前と年齢のクラス。
	 */
	public class Person implements Comparable {
		/** 名前 */
		public String name;
		/** 年齢 >= 0 */
		public int age;

		/** 比較メソッド。ageの昇順にソートしたい。
		 * @param object 比較対象のPersonオブジェクト
		 */
		public int compareTo(Object object) {
			Person operand = (Person) object;
			if (this.age < operand.age) {
				return -1;
			} else if (this.age > operand.age) {
				return 1;
			} else {
				return 0;
			}
		}
	}
という感じです。
return this.age - operand.age;
とする手も ありますが、この場合は年齢だから問題になりませんが、整数同士の引き算は オーバーフローを発生させる可能性がありますので、 面倒でもifで評価したほうが安全でしょう。

Comparableをimplementsしていれば、

	Person[] personArray = getPersonArrayFromAnywhere();
	java.util.Arrays.sort(personArray);
という風にjava.util.Arrays.sort()を使うことが出来ます。逆順にソート したい場合は、compareTo()メソッドで返す値を正負逆にすれば良いわけです。 String等のクラスもComparableがimplementsされています。

Comparableがimplementsされているクラスのオブジェクトであれば、その Collection、例えばListをソートすることも容易です。

	List personList = getPersonList()	// Personオブジェクトのリスト
	Collections.sort(personList);
とすれば、personListがソートされます。

Comparatorを作成する方法

自分で作成しているクラスならComparableをimplementsすれば良いのですが、 自分では内部をさわることが出来ないクラスの場合は困ります。ラッピング するようなクラスを作ってしまうことも出来ますが、ソートをするだけなら java.util.Comparatorをimplementsするクラスを別に用意したほうが簡単です。

例えばStringの配列を逆順にソートする場合を考えましょう。Stringは Comparableをimplementsしていますが、これは昇順ソートを前提にしています。 しかもStringはfinalクラスですので継承してクラスを作ることが出来ません。 Stringを含むクラスを作るのも何だし、という場合にComparatorの登場と なります。

java.util.Comparatorインタフェースはcompare()とequals()という二つの メソッドを定義することになっていますが、equals()は、Comparator自身の 等値性の話なので、ソートには直接は関係しません。必要なのはcompare() メソッドの方です。これはComparableのcompareTo()と似ていて、2つの引数 のうち、1つ目の引数が小さければ負の値、同じならば0、大きければ正の値を 返すように実装します。逆順ソートの場合は正負を反対にします。 Stringの逆順ソートを行う場合は、

	public class ReverseComparator implements java.util.Comparator {
		public int compare(Object object1, Object object2) {
			String string1 = (String) object1;
			String string2 = (String) object2;
			return (string1.compareTo(string2)) * (-1);
		}
	}
という風にComparatorの実装を作成します。すると、
	String[] stringArray = getStringArrayFromAnywhere();
	Arrays.sort(stringArray, new ReverseComparator());
と、sort()に配列とともにReverseComparatorのインスタンスを渡すことで、 逆順ソートが実現できます。

Collectionの場合もComparatorを渡すことが出来ます。上記の文字列の逆順 ソートの場合、

	List stringList = getStringListFromAnywhere();
	Collections.sort(stringList, new ReverseComparator());
で出来ます。まじめにソートのアルゴリズムについて勉強しておく事は 重要ですが、実装にあたってはあるものを利用するという考えも重要です。 そういう場合はjava.util.Arraysやjava.util.Collectionsといった ユーティリティクラスが便利です。


人材開発室 PoisonSoft