2009年10月30日金曜日

Java でオブジェクトの比較とソート

Haskell の代数的データ型を比較、特定の基準でソート を試したので、ついでに Java でも。てゆうか、総称型が導入されてから、JDK で言うと 1.5 以降 Java を触ってないので API のドキュメントを読んでも隔世の感が。。 ^^;

 

「人」クラスの定義

前回と同様、「人」が「名前」「年齢」を持っているとして、

public class Person {

    private String name;
    private int age;

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

    String getName() {
        return this.name;
    }

    int getAge() {
        return this.age;
    }

    @Override
    public String toString() {
        return this.name + ":" + this.age;
    }
}

 

Comparable<T> を実装して比較可能に

Person クラスを比較可能にするには、Comparable インターフェイスを実装。

インタフェース Comparable<T>

型パラメータ:
T - the type of objects that this object may be compared to

昔は <T> なんてなかったので、久しぶりに見ると混乱するなぁ~ (+_+)

Haskell で言うなら、

class Eq a => Ord a where

の型変数 a に相当するということか。

 

クラス宣言において、Comparable を implements するとき、後ろに <具体的なクラス名> を入れる。

public class Person implements Comparable<Person> {

Haskell なら、

instance Ord Person where

 

Comparable<Person> を実装するには、compareTo メソッドを書く必要がある。ここでは「人」の年齢が人の順序を決めるものとして扱う。総称型を利用することによって、Object クラスをキャストして使わなくて済むところが以前より楽。

    public int compareTo(Person o) {
        return new Integer(this.age).compareTo(o.getAge());
    }

これで Personクラスのオブジェクトを比較できるようになった。

System.out.println(new Person("Tarou", 10).compareTo(new Person("Saburou", 30)));  // -1

 

ソート

次に上記で定義した比較によるソートを試す。リストを作成するには、ArraysasList を使うのが書きやすい。

public static <T> List<T> asList(T... a)

このメソッドも随分様変りしてるなぁ。。。以前は、

public static List asList(Object[] a)
(Arrays (Java 2 プラットフォーム SE v1.4.0) より)

引数の … は可変長の引数を表わすらしい。(cf. ライトニングJava (9) 可変長引数(3)) static の後の <T> は何を表わしているのか知らないけれど、とにかく使う分には、

        List<Person> persons = Arrays.asList(
                new Person("Saburou", 30),
                new Person("Jiro", 20),
                new Person("Tarou", 10),
                new Person("Hanako", 30));

これをソートするには、Collectionssort を使う。

        Collections.sort(persons);
        System.out.println(persons);   // [Tarou:10, Jiro:20, Saburou:30, Hanako:30]

しかし、型を見ると、

public static <T extends Comparable<? super T>> void sort(List<T> list)

うげぇ (@_@;) ますます分からん。。

 

Comparator でソートする基準を変更

ソートする基準を変えたい場合は、Comparator を使う。

例えば、「年齢が同じ場合、名前順にしたい」なら、

        Collections.sort(persons, new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                int c = new Integer(o1.getAge()).compareTo(o2.getAge());
                if (c != 0) {
                    return c;
                } else {
                    return o1.getName().compareTo(o2.getName());
                }
            }
        });
        System.out.println(persons);   // [Tarou:10, Jiro:20, Hanako:30, Saburou:30]

これも Comparator<Person> とクラスを指定すると、compare メソッドの引数のクラスが決まるようで、キャストが必要なくなっている。

 

あ~、Java の総称型は完全にスルーしていたので読めない。。パタッ(o_ _)o~†

しかし、これからは Scala の時代になっていくのかなぁ?

 

全体