Je suis nouveau sur Java 8. Je veux juste trier par nom. Mais la condition est la suivante: s’il existe des noms en double, ils doivent être triés par âge.
Par exemple, ma contribution est
tarun 28
arun 29
varun 12
arun 22
et la sortie devrait être
arun 22
arun 29
tarun 28
varun 12
Mais je reçois quelque chose comme
varun 12
arun 22
tarun 28
arun 29
Cela signifie qu'il est trié uniquement par âge ou par nom.
C'est le code qui est implémenté:
Classe POJO:
class Person {
String fname;
int age;
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public Person(String fname, int age) {
this.fname = fname;
this.age = age;
}
@Override
public String toString() {
return fname + age;
}
}
Classe de test:
public class Test {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("tarun", 28));
persons.add(new Person("arun", 29));
persons.add(new Person("varun", 12));
persons.add(new Person("arun", 22));
Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person t, Person t1) {
return t.getAge() - t1.getAge();
}
});
System.out.println(persons);
}
}
Actuellement, vous comparez a) un seul attribut et b) n’utilisez pas vraiment les nouvelles fonctionnalités de Java 8.
Avec Java 8, vous pouvez utiliser références de méthodes et des comparateurs chaînés, comme ceci:
Collections.sort(persons, Comparator.comparing(Person::getFname)
.thenComparingInt(Person::getAge));
Cela comparera deux instances Person
en premier par leur fname
et - si cela est égal - par leur age
(avec une légère optimisation à thenComparingInt
pour éviter la boxe).
Vous devez d'abord comparer les noms. Si les noms sont les mêmes, alors et seulement alors le résultat dépend de la comparaison de l'âge
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("tarun", 28));
persons.add(new Person("arun", 29));
persons.add(new Person("varun", 12));
persons.add(new Person("arun", 22));
Collections.sort(persons, new Comparator<Person>() {
public int compare(Person t, Person t1) {
int comp = t.getFname().compareTo(t1.getFname());
if (comp != 0) { // names are different
return comp;
}
return t.getAge() - t1.getAge();
}
});
System.out.println(persons);
}}
si vous voulez passer d’ascendant à décroissant, il suffit de changer le signe. par exemple.
return -comp;
ou échangez la personne
prénom
int comp = t1.getFname().compareTo(t.getFname());
âge
return t1.getAge() - t.getAge();
Vous êtes sur le bon chemin, mais votre méthode compare
est incomplète.
Étant donné que compare
est appelé pour décider quel élément de chaque paire doit être placé avant l'autre, il doit inclure toute la logique de comparaison, pas seulement celle qui permet de départager. Votre code trie uniquement sur l'âge, ignorant complètement le nom.
La logique devrait aller comme ceci:
t.getFname().compareTo(t1.getFname())
La manière correcte de comparer des nombres entiers est d'utiliser la méthode statique Integer.compare
, c'est-à-dire Integer.compare(t.getAge(), t1.getAge())
.
Votre Comparator
ne fait que trier par âge et non par nom.
Vous pouvez l'essayer comme ça:
new Comparator<Person>() {
@Override
public int compare(Person t, Person t1) {
int ret = t.getFname().compareTo(t1.getFname());
if (ret == 0) {
ret = Integer.compare(t.getAge(), t1.getAge());
}
return ret;
}
}
Vous pouvez également penser à implémenter Comparable<Person>
dans la classe Person
elle-même:
class Person implements Comparable<Person> {
@Override
public int compareTo(Person p) {
int ret = fname.compareTo(p.fname);
if (ret == 0) {
ret = Integer.compare(age, p.getAge());
}
return ret;
}
}
Ceci est simple une ligne comparaison en utilisant l'opérateur ternaire pour trier les objets. Pas besoin d'écrire autant si/else block .
Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person t1, Person t2) {
return t1.getFname().equals(t2.getFname()) ? t1.getAge()-t2.getAge() : t1.getFname().compareTo(t2.getFname());
}
});
Vous pouvez utiliser la méthode Comparator.comparing
, introduite dans Java 8, renvoie un objet Comparator qui utilisera le champ spécifié comme clé de tri.
final Function<Person, Integer> byAge = person -> person.getAge();
final Function<Person, String> byTheirName = person -> person.getFname();
System.out.println("Sorted in ascending order by age and name: ");
List<Person> sortedlist = people.stream()
.sorted(Comparator.comparing(byAge).thenComparing(byTheirName))
.collect(Collectors.toList());
sortedlist.forEach(System.out::println);
Nous avons d’abord créé deux expressions lambda, l’une pour indiquer l’âge d’une personne donnée et l’autre pour renvoyer le nom de cette personne. Nous avons ensuite combiné ces deux expressions lambda dans l'appel de la méthode sorted()
afin de comparer les deux propriétés. La méthode comparing()
a créé et renvoyé un comparateur à comparer en fonction de l'âge. Sur le comparateur renvoyé, nous avons appelé la méthode thenComparing()
pour créer une variable comparator
comparée en fonction de l'âge et du nom.