1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

オブジェクトソート時の順序関係を規定するには?

Last updated at Posted at 2016-02-06

以下のインターフェースのいずれかを実装したクラスを定義する必要がある。

  • java.lang.Comparable

    • Javaコアクラスが実装している
    • オブジェクト全体に自然順序づけを強制する。(compareToメソッド)
    • 実装したオブジェクトの配列はCollection.sort()もしくはArrays.sort()によってソートされる。
  • java.util.Comparator

    • クライアントが独自の順序でオブジェクトソートしたい時に使う。

Comparableインターフェース

public interface Comparable<T> {
	public int compareTo(T o);
}

Comparableを実装しているクラス
Integer, Double, File, Enum など...
Comparableインターフェースを実装したクラスは、保存されるオブジェクト自身で比較が行われる。

Comparableを実装しているInteger

具体的にIntegerクラスで、比較できる仕組みをみてみる。

public final class Integer extends Number implements Comparable<Integer> {
	public int compareTo(Integer anotherInteger) {
		return compare(this.value, anotherInteger.value);
	}
	// 保持する値の比較
	// 自Obj < 比較対象Obj ならば-1
	// 自Obj = 比較対象Obj ならば0
	// 自Obj > 比較対象Obj ならば1
	public static int compare(int x, int y) {
		return (x < y) ? -1 : ((x == y) ? 0 : 1);		
	}
}

使用例

// 並び替え
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(new Integer(5));
integerList.add(new Integer(2));
integerList.add(new Integer(3));
integerList.sort(null);
for (Integer integer : integerList) {
	System.out.println(integer);
} // 2 3 5
// 比較
System.out.println(new Integer(3).compareTo(new Integer(5))); // -1
System.out.println(new Integer(3).compareTo(new Integer(3))); // 0
System.out.println(new Integer(5).compareTo(new Integer(3))); // 1
List<String> stringList = new ArrayList<String>();
stringList.add("c");
stringList.add("d");
stringList.add("a");
stringList.sort(null);
for(String str : stringList) {
	System.out.println(str);
} // a c d

Comparatorインターフェース

public interface Comparator<T> {
	int compare(T o1, T o2);
	boolean equals(Object obj);
	default Comparator<T> reversed() {
		return Collections.reverseOrder(this);
	}
	// そのほかにもメソッドを持つ
	......
}

Comparatorによる独自順序づけとComparableによる自然順序づけとTreeSetの使用例

java.util.TreeMap

  • このクラスでは、格納する要素はComparableを実装したオブジェクトであることを前提とする。

  • Comparableを実装していないとエラーがでる。

class Employee implements Comparable<Employee>{
	private String name;
	private Integer id;
	private Date birth;

	public Employee(String name, Integer id, Date birth) {
		this.name = name;
		this.id = id;
		this.birth = birth;
	}

	public Integer getId() {
		return id;
	}

	public String getName() {
		return name;
	}
	public Date getBirth() {
		return birth;
	}

	public String toString() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
		Calendar cal = Calendar.getInstance();
		cal.setTime(birth);
		return "name=" + name + " id=" + id + " birth" + dateFormat.format(cal.getTime());
	}

	/**
	 * idを比較します
	 * @param obj1
	 * @param obj2
	 * @return
	 */
	public int compare(Employee obj1, Employee obj2) {
		return obj1.getId().compareTo(obj2.getId());
	}

	@Override
	public int compareTo(Employee o) {
		return compare(this, o);
	}
}
/**
 * EmployeeのIDを元に比較をします
 *
 */
class SortID implements Comparator<Employee> {
	@Override
	public int compare(Employee obj1, Employee obj2) {
		return obj1.getId().compareTo(obj2.getId());
	}
}
/**
 * EmployeeのBirthを元に比較をします
 *
 */
class SortBirth implements Comparator<Employee>{
	@Override
	public int compare(Employee o1, Employee o2) {
		return o1.getBirth().compareTo(o2.getBirth());
	}

}

class SortSample {
	public static void main(String[] args) {
		Calendar cal = Calendar.getInstance();
		cal.set(1990, 01, 05);
		Employee e1 = new Employee("aya", 20, cal.getTime());
		cal.set(1990, 01, 01);
		Employee e2 = new Employee("jon", 10, cal.getTime());
		cal.set(1990, 01, 02);
		Employee e3 = new Employee("ryu", 50, cal.getTime());

		TreeSet<Employee> treeset = new TreeSet<Employee>();
		treeset.add(e1);
		treeset.add(e2);
		treeset.add(e3);
		System.out.println("TreeSetに格納されたEmployeeのcompareTo()に基づきIDの昇順で表示");
		print(treeset);

		TreeSet<Employee> treesetBirth = new TreeSet<Employee>(new SortBirth());
		treesetBirth.add(e1);
		treesetBirth.add(e2);
		treesetBirth.add(e3);
		System.out.println("TreeSetに格納されたEmployeeをSortBirthで定義したbirthの昇順での表示");
		print(treeset);

		ArrayList<Employee> ary = new ArrayList<Employee>();
		ary.add(e1);
		ary.add(e2);
		ary.add(e3);
		System.out.println("ArrayList のインデックス順での表示");
		print(ary);

		Collections.sort(ary, new SortID());
		System.out.println("SortID で定義したid の昇順での表示");
		print(ary);

		Collections.sort(ary, new SortBirth());
		System.out.println("SortBirth で定義したbirthの昇順での表示");
		print(ary);
	}

	public static void print(Collection<Employee> ary) {
		for (Employee obj : ary) {
			System.out.println(obj);
		}
	}
}

実行結果

TreeSetに格納されたEmployeeのcompareTo()に基づきIDの昇順で表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
TreeSetに格納されたEmployeeをSortBirthで定義したbirthの昇順での表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
ArrayList のインデックス順での表示
name=aya id=20 birth1990/02/05
name=jon id=10 birth1990/02/01
name=ryu id=50 birth1990/02/02
SortID で定義したid の昇順での表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
SortBirth で定義したbirthの昇順での表示
name=jon id=10 birth1990/02/01
name=ryu id=50 birth1990/02/02
name=aya id=20 birth1990/02/05

TreeSetにStringを入れる

class TreeSetSample{
	  public static void main(String[] args) {
		    HashSet<String> hash = new HashSet<String>();
		    hash.add("D"); hash.add("B"); hash.add("C");
		    System.out.println("HashSet : " + hash);
		    TreeSet<String> tree = new TreeSet<String>();
		    tree.add("D"); tree.add("B"); tree.add("C");
		    System.out.println("TreeSet : " + tree);
		  }
}

StringでのComparableについて

StringクラスはComparableのcompareToを実装しつつ、
大文字小文字を無視するためにComparatorも定義してString.CASE_INSENSITIVE_ORDERフィールドを持っている。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }
}

class StringSortSample {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("B", "a", "123", "c");
		System.out.println("Collections.sortを使う");
		Collections.sort(list);
		System.out.println(list);
		System.out.println("String.CASE_INSENSITIVE_ORDERを使う");
		Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
		System.out.println(list);
		System.out.println("compareToIgnoreCaseを使う");
		Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2));
		System.out.println(list);
	}
}

実行結果

Collections.sortを使う
[123, B, a, c]
String.CASE_INSENSITIVE_ORDERを使う
[123, a, B, c]
compareToIgnoreCaseを使う
[123, a, B, c]
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?