web-dev-qa-db-fra.com

Comment trier Liste d'objets par propriété

J'ai cours simple 

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

et List<ActiveAlarm> con. Comment trier par ordre croissant par timeStarted, puis par timeEnded? Quelqu'un peut aider? Je connais en C++ avec un algorithme générique et un opérateur de surcharge <, mais je suis nouveau en Java.

124
Jennifer

Créez ActiveAlarm Implement _Comparable<ActiveAlarm>_ ou implémentez _Comparator<ActiveAlarm>_ dans une classe séparée. Puis appelez:

_Collections.sort(list);
_

ou

_Collections.sort(list, comparator);
_

En général, c'est une bonne idée d'implémenter Comparable<T> s'il n'y a qu'un seul ordre de tri "naturel" ... sinon (si vous arrive pour trier dans un ordre particulier, mais peut également vouloir en changer, il est préférable de mettre en œuvre Comparator<T> . Pour être honnête, cette situation particulière pourrait aller dans les deux sens ... mais je probablement resterais plus flexible Comparator<T> option.

EDIT: Exemple d'implémentation:

_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;
  }
}
_
135
Jon Skeet

Utilisation de Comparator

Par exemple:

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

À partir de Java 8, vous pouvez simplement utiliser l'expression lambda pour représenter une instance de comparateur.

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

Java 8 et réponse ci-dessus (utilisation d'expressions lambda)

En Java 8, les expressions Lambda ont été introduites pour rendre cela encore plus facile! Au lieu de créer un objet Comparator () avec tout son échafaudage, vous pouvez le simplifier comme suit: (En utilisant votre objet comme exemple)

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

ou même plus court:

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

Cette déclaration équivaut à ce qui suit:

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

Pensez aux expressions Lambda comme exigeant uniquement que vous insériez les parties pertinentes du code: la signature de la méthode et ce qui est renvoyé.

Une autre partie de votre question portait sur la comparaison des champs. Pour ce faire avec les expressions Lambda, vous pouvez utiliser la fonction .thenComparing() pour combiner efficacement deux comparaisons en une seule:

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

Le code ci-dessus triera d'abord la liste par timeStarted, puis par timeEnded (pour les enregistrements qui ont le même timeStarted).

Une dernière remarque: il est facile de comparer des primitives 'longues' ou 'int', vous pouvez simplement les soustraire de l'autre. Si vous comparez des objets ('Long' ou 'String'), je vous suggère d'utiliser leur comparaison intégrée. Exemple:

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

EDIT: Merci à Lukas Eder de m'avoir dirigé vers la fonction .thenComparing().

35
John Fowler

Nous pouvons trier la liste de deux manières:

1. Using Comparator : Lorsque vous devez utiliser la logique de tri à plusieurs endroits Si vous souhaitez utiliser la logique de tri à un seul endroit, vous pouvez écrire une classe interne anonyme comme suit, ou bien extraire la comparateur et l'utiliser à plusieurs endroits

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

Nous pouvons avoir un contrôle nul pour les propriétés, si nous aurions pu utiliser "Long" au lieu de "long".

2. Utilisation de Comparable (ordre naturel) : Si l'algorithme de tri s'en tient toujours à une propriété: Écrit une classe qui implémente la méthode 'Comparable' et substitue la méthode 'compareTo' comme défini ci-dessous

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

}

méthode de tri des appels à trier selon un ordre naturel

Collections.sort(list);
19
Jagadeesh

En Java8 +, cela peut être écrit en une seule ligne comme suit,

collectionObjec.sort (comparator_lamda) ou comparator.comparing (CollectionType :: getterOfProperty)

code: 

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

ou

ListOfActiveAlarmObj.sort(Comparator.comparing(ActiveAlarm::getTimeStarted))
4
Karthikeyan
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;
        }
 }

Cela devrait vous donner une idée approximative. Une fois que cela est fait, vous pouvez appeler Collections.sort() sur la liste. 

4
Kal

Depuis Java8, cela peut être fait encore plus proprement avec une combinaison de Comparator et Lambda expressions

Par exemple:

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
Mathias G.

Guava's 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

En Java, vous devez utiliser la méthode statique Collections.sort. Voici un exemple de liste d'objets CompanyRole, triés d'abord par début, puis par fin. Vous pouvez facilement vous adapter à votre propre objet. 

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;
            }
        }
    });
}
1
Richard H

Comme mentionné, vous pouvez trier par:

  • Rendre votre objet implémenter Comparable 
  • Ou passez un Comparator à Collections.sort

Si vous faites les deux, la Comparable sera ignorée et Comparator sera utilisée. Cela aide les objets de valeur à posséder leur propre Comparable logique, ce qui est le tri le plus raisonnable pour votre objet de valeur, chaque cas d'utilisation individuel ayant sa propre implémentation.

0
Alireza Fattahi

Vous pouvez appeler Collections.sort () et transmettre un comparateur que vous devez écrire pour comparer différentes propriétés de l'objet.

0
Liv

Vous pouvez utiliser Collections.sort et transmettre votre propre Comparator<ActiveAlarm>

0
MarcoS