Jak posortować listę obiektów według jakiejś właściwości


Mam prostą klasę
public class ActiveAlarm {
public long timeStarted;
public long timeEnded;
private String name = "";
private String description = "";
private String event;
private boolean live = false;
}

i
List & < ActiveAlarm & >
end. Jak posortować w kolejności rosnącej
timeStarted
, a następnie
timeEnded
? Czy ktoś może pomóc? Wiem w C ++ z ogólnym algorytmem i operatorem przeciążenia & < ,, ale jestem nowy w Javie.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Utwórz
ActiveAlarm
implementację
Comparable & < ActiveAlarm & >
lub zaimplementuj
Comparator & < ActiveAlarm & >
w osobnej klasie . Wtedy zadzwoń:
Collections.sort(list);

lub
Collections.sort(list, comparator);

Ogólnie rzecz biorąc, warto wdrożyć
Comparable<T>
http://download.oracle.com/jav ... .html
jeśli istnieje jeden porządek sortowania „naturalny” ... w przeciwnym razie (jeśli tak
chcesz sortować w określonej kolejności, ale równie łatwo możesz wybrać inną) lepiej zaimplementować
Comparator<T>
http://download.oracle.com/jav ... ml... Szczerze mówiąc, ta konkretna sytuacja może pójść w dowolnym kierunku ... ale chciałbym,

prawdopodobnie

utknąłem na bardziej elastycznym
Komparator & < T & >
.
EDYCJA: przykładowa realizacja:
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;
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Za pomocą
Comparator
http://download.oracle.com/jav ... .html

na przykład

:
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));
}
});

Od wersji Java 8 można po prostu użyć wyrażenia lambda do reprezentowania instancji komparatora.
Collections.sort(scores, (s1, s2) -> {/* compute and return int */ });
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Odpowiedź JAVA 8 i nowsza (używając wyrażeń

Lambda)
Java 8 wprowadziła wyrażenia Lambda, aby było to jeszcze łatwiejsze! Zamiast tworzyć obiekt Comparator () z całym jego szkieletem, możesz to uprościć w następujący sposób: (używając swojego obiektu jako przykładu)
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted);

lub jeszcze krócej:
Collections.sort(list, Comparator.comparingInt(ActiveAlarm ::getterMethod));

To jedno stwierdzenie jest równoważne z następującym:
Collections.sort(list, new Comparator<ActiveAlarm>() {
@Override
public int compare(ActiveAlarm a1, ActiveAlarm a2) {
return a1.timeStarted - a2.timeStarted;
}
});

Wyrażenia lambda należy traktować jako coś, co wystarczy umieścić w odpowiednich częściach kodu: sygnaturze metody i tym, co jest zwracane.
Druga część Twojego pytania dotyczyła sposobu porównywania z wieloma polami. Aby to zrobić za pomocą wyrażeń Lambda, możesz użyć funkcji
.thenComparing ()
, aby skutecznie połączyć dwa porównania w jedno:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.timeStarted-a2.timeStarted 
.thenComparing ((ActiveAlarm a1, ActiveAlarm a2) -> a1.timeEnded-a2.timeEnded));

Powyższy kod posortuje listę najpierw według
timeStarted
, a następnie według
timeEnded
(dla tych wpisów, które mają ten sam
timeStarted
).
Ostatnia uwaga: łatwo jest porównać prymitywy „długie” lub „int”, można po prostu odjąć jeden od drugiego. Jeśli porównujesz obiekty („Long” lub „String”), sugeruję użycie ich porównania w wierszu. Przykład:
Collections.sort(list, (ActiveAlarm a1, ActiveAlarm a2) -> a1.name.compareTo(a2.name) );

EDYCJA: Podziękowania dla Lucasa Edera za wskazanie mi funkcji
.thenComparing ()
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Listę możemy posortować na dwa sposoby

:

1. Korzystanie z komparatora
: w razie potrzeby użyj logiki sortowania w wielu miejscach
Jeśli chcesz użyć logiki sortowania w jednym miejscu, możesz napisać anonimową klasę wewnętrzną, taką jak ta, lub możesz wyodrębnić komparator i użyć go w kilku miejscach.
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;
}
});

Możemy poprosić null o sprawdzenie właściwości, jeśli moglibyśmy użyć „Long” zamiast „long”.

2. Używanie porównywalnych (porządek naturalny)
: jeśli algorytm sortowania będzie zawsze trzymał się jednej właściwości:
napisz klasę, która implementuje metodę „Comparable” i zastępuje metodę „compareTo”, jak zdefiniowano poniżej
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;
}

}
wywołanie metody sortowania w celu sortowania na podstawie naturalnego porządku
Collections.sort(list);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W java8 + można to zapisać w jednej linii w ten sposób,
collectionObjec.sort (Comparator_lamda) lub Comparator.comparison (CollectionType :: getterOfProperty)
kod :
ListOfActiveAlarmObj.sort((a,b->a.getTimeStarted().compareTo(b.getTimeStarted())))

lub
ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

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;
}
}

To powinno dać ci ogólne pojęcie. Gdy to zrobisz, możesz wywołać
Collections.sort ()
nad listą.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Od wersji Java8 można to uczynić jeszcze czystszym za pomocą tej kombinacji
Comparator
http://download.oracle.com/jav ... .html
i
Lambda expressions
https://docs.oracle.com/javase ... .html

na przykład

:
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);
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

ComparisonChain
https://google.github.io/guava ... .html
guawa przez:
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();
}});
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

możesz użyć
Collections.sort
http://download.oracle.com/jav ... .List,%20java.util.Comparator%29
i przenieś własne
Comparator<ActiveAlarm>
http://download.oracle.com/jav ... .html
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W Javie musisz użyć statycznej metody
Collections.sort
. Oto przykład listy obiektów CompanyRole posortowanych najpierw na początku, a następnie na końcu. Możesz łatwo dostosować się do własnego obiektu.
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;
}
}
});
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz wywołać Kolekcje.sort () i przekazać do komparatora, który musisz napisać, aby porównać różne właściwości obiektu.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jak wspomniano, możesz sortować według:
  • Tworząc obiekt implementacji
    porównywalny
  • Lub przejdź z
    Comparator
    do
    Collections.sort

Jeśli zrobisz jedno i drugie,
Comparable
zostanie zignorowane i użyty zostanie
Comparator
. Pomaga, aby obiekty wartości miały własne wartości logiczne
Comparable
, co jest najbardziej rozsądnym sortowaniem dla twojego obiektu wartości, podczas gdy każdy indywidualny przypadek użycia ma swoją własną implementację.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się