일부 속성별로 개체 목록을 정렬하는 방법


145

간단한 수업이 있습니다

public class ActiveAlarm {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;
}

그리고 List<ActiveAlarm>죄수. 을 기준으로 오름차순으로 정렬 timeStarted한 다음 timeEnded? 아무도 도와 줄 수 있습니까? 나는 일반적인 알고리즘과 과부하 연산자 <를 사용하여 C ++에서 알고 있지만 Java를 처음 사용합니다.


이 게시물의 @Yishai의 답변은 비교기 체인을 사용하여 사용자 정의 정렬 및 그룹 정렬 (여러 인수)에 열거 형을 우아하게 사용하는 방법을 보여줍니다.
gunalmel

답변:


140

어느 만든다 ActiveAlarm구현 Comparable<ActiveAlarm>하거나 구현하는 Comparator<ActiveAlarm>별도의 클래스에서. 그런 다음 전화 :

Collections.sort(list);

또는

Collections.sort(list, comparator);

일반적으로, 구현하는 좋은 아이디어이다 Comparable<T>, 그렇지 않으면 ... 하나의 "자연"정렬 순서가 있다면 (당신이 경우 일어날 특정 순서로 정렬 할 것이 아니라, 동등하게 쉽게 다른 일을 할 수 있습니다) 그것을 구현하는 것이 좋습니다 Comparator<T>. 이 특정 상황은 솔직히 말해서 어느 쪽이든 갈 수 있지만 더 유연한 옵션을 고수 할 것 입니다Comparator<T> .

편집 : 샘플 구현 :

public class AlarmByTimesComparer implements Comparator<ActiveAlarm> {
  @Override
  public int compare(ActiveAlarm x, ActiveAlarm y) {
    // TODO: Handle null x or y values
    int startComparison = compare(x.timeStarted, y.timeStarted);
    return startComparison != 0 ? startComparison
                                : compare(x.timeEnded, y.timeEnded);
  }

  // I don't know why this isn't in Long...
  private static int compare(long a, long b) {
    return a < b ? -1
         : a > b ? 1
         : 0;
  }
}

1
구현이 훨씬 사소하기 때문에 compare () 함수는 Long에 없습니다. return a-b;
papercrane

5
@ papercrane : 아니요, 오버플로 이유로 실패합니다. 고려하십시오 a = Long.MIN_VALUE, b = 1.
Jon Skeet

3
API 19로 (킷캣) 롱 이제이.compare
마틴 Marconcini

123

사용 Comparator

예를 들어 :

class Score {

    private String name;
    private List<Integer> scores;
    // +accessor methods
}

    Collections.sort(scores, new Comparator<Score>() {

        public int compare(Score o1, Score o2) {
            // compare two instance of `Score` and return `int` as result.
            return o2.getScores().get(0).compareTo(o1.getScores().get(0));
        }
    });

Java 8부터는 람다 식을 사용하여 Comparator 인스턴스를 나타낼 수 있습니다.

Collections.sort(scores, (s1, s2) -> { /* compute and return int */ });

1
무엇을 compareTo()합니까? 그거 어디서 났어? 어디서 정의해야합니까?
Asqiir

1
@Asqiir을 getScores()위한 게터이며 scores이는이다 List<Integer>. 당신이 물건 getScores().get(0)을 얻을 때 Integer. Integer이미 compareTo(anotherInteger)메소드가 구현되어 있으므로 정의 할 필요가 없습니다.
walen

get (0)은 무엇입니까?
Ali Khaki

1
고마워 매력처럼 작동합니다 (.get (0) 부분없이 사용합니다). 주문을 어떻게 되돌릴 수 있습니까?

53

자바 8 이상 답변 (람다 식 사용)

Java 8에서는 Lambda 표현식이 도입되어 더욱 쉬워졌습니다! 모든 스캐 폴딩으로 Comparator () 객체를 만드는 대신 다음과 같이 단순화 할 수 있습니다. (객체를 예제로 사용)

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);

또는 더 짧게 :

Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));

그 진술은 다음과 같습니다.

Collections.sort(list, new Comparator<ActiveAlarm>() {
    @Override
    public int compare(ActiveAlarm a1, ActiveAlarm a2) {
        return a1.timeStarted - a2.timeStarted;
    }
});

Lambda 표현식은 코드의 관련 부분 (메소드 서명 및 반환되는 항목) 만 입력하면된다고 생각하십시오.

질문의 또 다른 부분은 여러 필드와 비교하는 방법이었습니다. Lambda 표현식으로이를 수행하려면이 .thenComparing()함수를 사용 하여 두 비교를 하나로 결합 할 수 있습니다 .

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted             
       .thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded)
);

위의 코드는 목록을 먼저 정렬 timeStarted한 다음 timeEnded(같은 레코드에 대해) 정렬합니다 timeStarted.

마지막 참고 사항 : 'long'또는 'int'프리미티브를 쉽게 비교할 수 있습니다. 서로를 빼면됩니다. 객체 ( 'Long'또는 'String')를 비교하는 경우 기본 제공 비교를 사용하는 것이 좋습니다. 예:

Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );

편집 : .thenComparing()기능을 알려주는 Lukas Eder에게 감사드립니다 .


4
새로운 Java 8 API를 좋아하실 것입니다 Comparator.comparing().thenComparing().
Lukas Eder

1
돌아 오는 차이로 조심하십시오. 오버플로가 발생하면 잘못된 결과를 얻을 수 있습니다.
krzychu

2
이것은 명백한 자연 순서가 없다고 가정하면 IMHO가 더 쉬운 정렬 방법입니다. Collections더 이상 전화 할 필요가 없으며 목록으로 직접 전화 할 수 있습니다. 예 :myList.sort(Comparator.comparing(Address::getZipCode).thenComparing(Compartor.comparing(Address::getStreetName));
CeePlusPlus

20

다음 두 가지 방법 중 하나로 목록을 정렬 할 수 있습니다.

1. 비교기 사용 : 여러 장소에서 정렬 논리를 사용해야하는 경우 단일 장소에서 정렬 논리를 사용하려면 다음과 같이 익명 내부 클래스를 작성하거나 비교기를 추출하여 여러 위치에서 사용할 수 있습니다.

  Collections.sort(arrayList, new Comparator<ActiveAlarm>() {
        public int compare(ActiveAlarm o1, ActiveAlarm o2) {
            //Sorts by 'TimeStarted' property
            return o1.getTimeStarted()<o2.getTimeStarted()?-1:o1.getTimeStarted()>o2.getTimeStarted()?1:doSecodaryOrderSort(o1,o2);
        }

        //If 'TimeStarted' property is equal sorts by 'TimeEnded' property
        public int doSecodaryOrderSort(ActiveAlarm o1,ActiveAlarm o2) {
            return o1.getTimeEnded()<o2.getTimeEnded()?-1:o1.getTimeEnded()>o2.getTimeEnded()?1:0;
        }
    });

'long'대신 'Long'을 사용할 수 있다면 속성을 null 검사 할 수 있습니다.

2. Comparable (natural ordering) 사용 : 정렬 알고리즘이 항상 하나의 속성을 고수하는 경우 : 'Comparable'을 구현하는 클래스를 작성하고 아래 정의 된대로 'compareTo'메소드를 재정의하십시오.

class ActiveAlarm implements Comparable<ActiveAlarm>{

public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;

public ActiveAlarm(long timeStarted,long timeEnded) {
    this.timeStarted=timeStarted;
    this.timeEnded=timeEnded;
}

public long getTimeStarted() {
    return timeStarted;
}

public long getTimeEnded() {
    return timeEnded;
}

public int compareTo(ActiveAlarm o) {
    return timeStarted<o.getTimeStarted()?-1:timeStarted>o.getTimeStarted()?1:doSecodaryOrderSort(o);
}

public int doSecodaryOrderSort(ActiveAlarm o) {
    return timeEnded<o.getTimeEnded()?-1:timeEnded>o.getTimeEnded()?1:0;
}

}

자연 순서에 따라 정렬하는 정렬 방법 호출

Collections.sort(list);

7

java8 +에서는 다음과 같이 한 줄로 작성할 수 있습니다.

collectionObjec.sort(comparator_lamda) 또는 comparator.comparing(CollectionType::getterOfProperty)

암호:

ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))
 

또는

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))

5
public class ActiveAlarm implements Comparable<ActiveAlarm> {
    public long timeStarted;
    public long timeEnded;
    private String name = "";
    private String description = "";
    private String event;
    private boolean live = false;

    public int compareTo(ActiveAlarm a) {
        if ( this.timeStarted > a.timeStarted )
            return 1;
        else if ( this.timeStarted < a.timeStarted )
            return -1;
        else {
             if ( this.timeEnded > a.timeEnded )
                 return 1;
             else
                 return -1;
        }
 }

그것은 당신에게 대략적인 아이디어를 줄 것입니다. 완료되면 Collections.sort()목록에서 전화 를 걸 수 있습니다 .


4

Java8부터는 ComparatorLambda expressions

예를 들어 :

class Student{

    private String name;
    private List<Score> scores;

    // +accessor methods
}

class Score {

    private int grade;
    // +accessor methods
}

    Collections.sort(student.getScores(), Comparator.comparing(Score::getGrade);

2

구아바의 ComparisonChain :

Collections.sort(list, new Comparator<ActiveAlarm>(){
            @Override
            public int compare(ActiveAlarm a1, ActiveAlarm a2) {
                 return ComparisonChain.start()
                       .compare(a1.timestarted, a2.timestarted)
                       //...
                       .compare(a1.timeEnded, a1.timeEnded).result();
            }});


1

자바에서는 정적 Collections.sort메소드 를 사용해야합니다 . 다음은 CompanyRole 객체 목록의 예입니다 (처음으로 시작한 다음 끝으로 정렬). 자신의 물건에 쉽게 적응할 수 있습니다.

private static void order(List<TextComponent> roles) {

    Collections.sort(roles, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            int x1 = ((CompanyRole) o1).getBegin();
            int x2 = ((CompanyRole) o2).getBegin();

            if (x1 != x2) {
                return x1 - x2;
            } else {
                int y1 = ((CompanyRole) o1).getEnd();
                int y2 = ((CompanyRole) o2).getEnd();
                return y2 - y1;
            }
        }
    });
}

0

Collections.sort ()를 호출하고 객체의 다른 속성을 비교하기 위해 작성해야하는 Comparator를 전달할 수 있습니다.


0

언급했듯이 다음을 기준으로 정렬 할 수 있습니다.

  • 객체 구현 Comparable
  • 아니면 통과 ComparatorCollections.sort

두 가지를 모두 수행 Comparable하면가 무시되고 Comparator사용됩니다. 이를 통해 가치 객체에는 가치 객체 Comparable에 가장 적합한 정렬 방식 인 자체 논리 가 있으며 각 개별 사용 사례에는 자체 구현 방식이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.