-
Collections.sort()와 Arrays.sort()의 기본 정렬 기준은 오름차순이다. 숫자는 물론이고 문자열에 대해서도 마찬가지이므로 사전 순서로 정렬된다. "abc"는 "acc"보다 앞선다. 내림차순을 해야 할 때는 무언가 바꿔줘야 한다. 값이 중복될 때는 추가적인 기준을 만들 수 있다.
public class Car { String name; int PS; double zeroToHundred; Car(String name, int PS, double zeroToHundred) { this.name = name; this.PS = PS; this.zeroToHundred = zeroToHundred; } String getName() { return name; } int getPS() { return PS; } double getzeroToHundred() { return zeroToHundred; } }
public class CarMain { public static void main(String[] args) { Car[] cars = new Car[5]; cars[0] = new Car("Bentley Continental GT V8", 550, 4.0); cars[1] = new Car("Porsche 911 Carrera Coupe", 385, 4.2); cars[2] = new Car("Jaguar F-Type", 380, 4.4); cars[3] = new Car("BMW M8 Competition Coupe", 625, 3.2); cars[4] = new Car("Mercedes-Benz AMG GT", 639, 3.2); Arrays.sort(cars); } }
자동차의 이름, 마력, 제로백의 정보가 담긴 Car 배열이 정의됐다. 정렬된 상태가 아니므로 이름을 사전 순으로 정렬해도 되고 마력이나 제로백을 기준해서 정렬해도 된다. 일단 제로백을 기준으로 해보자.
정렬 함수는 sort()를 사용할 건데 Arrays, Collections에 둘 다 있기 때문에 어떤 것을 사용해야 할지 알아야 한다. 공식 문서를 살펴 보면 Arrays.sort()는 매개변수로 기본 자료형의 배열 변수를 받고 사용자 정의 타입의 배열 변수는 T[] 타입으로 받는다. 정렬 알고리즘은 피봇을 두 개 쓰는 퀵 정렬이다. 피봇을 하나만 쓸 때보다 빠르다고 나와 있는데 정확한 이유는 아직 모른다.
Collections.sort()는 List 인터페이스를 구현한 컬렉션만을 매개변수로 받는다. 정렬 알고리즘은 안정 합병 정렬이다. 정렬이 안정적이라는 말은 정렬되지 않은 상태에서 같은 키 값을 가진 원소의 순서가 정렬 후에도 유지된다는 의미다. 위 코드를 실행하면 다음과 같은 오류가 생긴다.
class Car cannot be cast to class java.lang.Comparable
Arrays가 Car 클래스의 무엇을 기준해 정렬할지 알 수 없기 때문에 일어난 오류다. 해결 방법은 크게 두 가지. 첫 번째는 Comparable 인터페이스를 상속받아 compareTo() 함수를 오버라이딩하는 방법이고 다른 하나는 Comparator 인터페이스를 상속받은 클래스로 만든 객체를 Arrays.sort()의 두 번째 매개변수로 넘겨주거나 익명 클래스를 정의하는 방법이다. 첫 번째 방법으로는 내림차순으로 정렬할 것이고 두 번째 방법으로는 두 개의 기준으로 사용해 정렬할 것이다.
제로백 내림차순을 하기 위해 Comprable<Car>를 implements 한 후 compareTo()를 오버라이딩한다. Integer 클래스에 있는 compare()를 이용하면 편하다. compare()는 다음과 같이 구현되어 있다. -1을 반환하면 오름차순으로 정렬하고 0을 반환하면 정렬하지 않고 1을 반환하면 내림차순으로 정렬한다.
public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
이 함수를 이용해서 오버라이딩한다. 직접 풀어써도 된다. 대소 비교할 때 위치를 바꾸면 오름차순이 된다. 다시 실행해보면 오류 없이 잘 실행된다.
@Override public int compareTo(Car o) { return Integer.compare(PS, o.getPS()); }
@Override public int compareTo(Car o) { return o.getzeroToHundred() < zeroToHundred ? -1 : o.getzeroToHundred() == zeroToHundred ? 0 : 1; }
M8은 AMG GT보다 마력이 조금 약하지만 제로백은 둘 다 3.2초로 같다. 제로백이 같은 자동차는 마력으로 오름차순 해보자. 이번에는 Comparator 인터페이스를 사용할 것이다.
Arrays.sort(cars, new Comparator() { @Override public int compare(Car o1, Car o2) { if (o1.getzeroToHundred() == o2.getzeroToHundred()) { // 마력 오름차순 return o1.getPS() < o2.getPS() ? -1 : o1.getPS() == o2.getPS() ? 0 : 1; } //제로백 내림차순 return o1.getzeroToHundred() > o2.getzeroToHundred() ? -1 : o1.getzeroToHundred() == o2.getzeroToHundred() ? 0 : 1; } });
만약 익명 클래스를 사용하고 싶지 않다면 Comparator를 상속받는 클래스를 새로 정의해서 오버라이드해서 사용한다. 그런 다음 해당 클래스를 매개변수로 넘긴다.
import java.util.Comparator; public class MyComparator implements Comparator{ @Override public int compare(Car o1, Car o2) { if (o1.getzeroToHundred() == o2.getzeroToHundred()) { // 마력 내림차순 return o1.getPS() > o2.getPS() ? -1 : o1.getPS() == o2.getPS() ? 0 : 1; } //제로백 오름차순 return o1.getzeroToHundred() < o2.getzeroToHundred() ? -1 : o1.getzeroToHundred() == o2.getzeroToHundred() ? 0 : 1; } }
public static void main(String[] args) { // .. Arrays.sort(cars, new MyComparator()); // print }
이차원 배열도 정렬할 수 있다. 사용법은 다음과 같다. 오른쪽 인덱스가 기준이 된다.
import java.util.Arrays; import java.util.Comparator; public class SortTest { public static void main(String[] args) { double[][] test = new double[5][2]; test[0][0]=200.0; test[0][1]=0.20; test[1][0]=100.0; test[1][1]=0.50; test[2][0]=10.0; test[2][1]=0.95; test[3][0]=220.0; test[3][1]=0.35; test[4][0]=140.0; test[4][1]=0.10; Arrays.sort(test, new Comparator<double[]>() { @Override public int compare(double[] o1, double[] o2) { // TODO Auto-generated method stub return Double.compare(o2[1], o1[1]); // 내림 차순 } }); for (int i = 0; i < 5; ++i) { for (int j = 0; j < 2; ++j) { System.out.printf("%.2f ", test[i][j]); } System.out.println(); } } }
'개발 > 자바' 카테고리의 다른 글
추상 클래스는 무엇 (0) 2020.03.19 참조변수에 대한 작은 오해 (0) 2020.03.16 배열 탐색도 연산이다 (0) 2020.03.11 객체의 final 변수 (0) 2020.03.10 환경변수의 시스템 path에 jdk/bin을 넣는 이유 (0) 2020.02.20