Alors que j'essaie de comprendre comment utiliser correctement le comparateur
, j'essaie de trier mes employés
dans un HashSet
. J'ai donc fait ceci:
Queue<Employee> list = new PriorityQueue<Employee>((a,b)->a.getAge()-b.getAge());
Comme vous pouvez le voir, j'ai essayé de le trier par âge, mais lorsque j'utilise cette expression lambda, cela produit une erreur de compilation, donc je suppose que quelque chose ne va pas. t ici.
Voici ma classe Employee
:
class Employee { String name; int age; // constructor, getters and setters }
Modifier : p>
Avec une PriorityQueue, cela fonctionne parfaitement:
Set<Employee> EmployeeSet = new HashSet<Employee>((a,b)->a.getAge()-b.getAge());
Pourquoi?
3 Réponses :
Vous pouvez utiliser un TreeSet
qui garantit un Set
ordonné basé sur le Comparator
Queue<Employee> list = new PriorityQueue<>(Comparator.comparingInt(Employee::getAge));
Le HashSet
d'autre part n'accepte pas un comparateur
dans son constructeur pour l'initialisation.
Modifier :
Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge)); // (a, b) -> a.getAge() - b.getAge() >>> Comparator.comparingInt(Employee::getAge
fonctionne bien puisque, PriorityQueue
est à nouveau une collection ordonnée qui accepte un comparateur
dans l'un des ses constructeurs.
Si vous vous demandez toujours, commandé et la collecte non ordonnée est la principale différence ici.
D'un point de vue mécanique, un HashSet
ne repose pas sur un comparateur
ou sur l'interface Comparable
pour déterminer l'ordre ou l'unicité; à la place, il repose sur le hashCode
des éléments individuels que vous placez à l'intérieur.
C'est pourquoi vous ne pouvez pas l'ajouter comme paramètre de constructeur; cela n'a aucun sens d'essayer d'insérer dans une carte de hachage des valeurs qui ont un ordre naturel. Sauf indication contraire de l'implémentation de l'ensemble, les ensembles sont par défaut non ordonnés ; HashSet
est une implémentation non ordonnée d'un ensemble.
La raison pour laquelle PriorityQueue
et TreeMap
fonctionnent avec des comparateurs et des éléments Comparables
est due à la façon dont ils sont structurés. Les éléments de commande PriorityQueue
et TreeMap
dans l'ordre naturel , donc avoir un Comparateur
pour piloter cela en l'absence de vos éléments implémentant Comparable
peut être souhaitable. Ces structures de données sont ordonnées , donc imposer un ordre personnalisé est une fonctionnalité pour celles-ci.
Comme d'autres l'ont noté, HashSet
est un ensemble non ordonné, et il ne peut donc pas prendre un comparateur qui fournit un ordre de tri. Vous voudrez peut-être utiliser un ensemble trié tel que TreeSet
à la place.
[Employee{name=Chris, age=26}, Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
Une note rapide sur les comparaisons numériques. L'utilisation de la soustraction pour comparer les valeurs int est dangereuse, car elle peut donner des résultats incorrects si la soustraction déborde. Cela ne se produira pas avec l'âge des personnes dont la fourchette typique n'entraînera pas de débordement. Mais si quelqu'un copiait ce code et l'appliquait à des valeurs différentes, cela pourrait entraîner des bogues. Au lieu de cela, je recommande d'utiliser les méthodes utilitaires Comparator
pour construire la bonne fonction de comparaison:
Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge) .thenComparing(Employee::getName));
Cela triera effectivement les employés par âge. Cependant ...
employeeList.sort(Comparator.comparingInt(Employee::getAge)); // before [Employee{name=Terry, age=37}, Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Chris, age=26}] // after [Employee{name=Kelly, age=26}, Employee{name=Chris, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
Nous avons ajouté quatre employés, mais il n'y a que trois employés dans l'ensemble! Aussi:
System.out.println(employeeSet.contains(kelly)); // true System.out.println(employeeSet.contains(chris)); // true
Comment est-ce possible? Le comparateur fourni est utilisé non seulement pour la commande , mais il est également utilisé pour déterminer l'appartenance à l'ensemble . Puisque Kelly et Chris ont le même âge, ce comparateur les considère comme égaux, donc un seul d'entre eux se retrouve dans l'ensemble.
Vous ne voulez probablement pas utiliser un TreeSet
pour faire le tri par valeurs qui peuvent avoir des doublons, car cela entraînera la perte d'éléments. Vous pouvez faire plusieurs choses. Premièrement, vous pouvez mettre les employés dans une liste puis trier la liste:
Employee terry = new Employee("Terry", 37); Employee kelly = new Employee("Kelly", 26); Employee brett = new Employee("Brett", 32); Employee chris = new Employee("Chris", 26); List<Employee> employeeList = Arrays.asList(terry, kelly, brett, chris); Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge)); employeeSet.addAll(employeeList); System.out.println(employeeSet); [Employee{name=Kelly, age=26}, Employee{name=Brett, age=32}, Employee{name=Terry, age=37}]
Ou, vous pouvez écrire un comparateur plus complexe qui différencie chaque élément des données d'entrée, de sorte qu'aucun deux ne soit considéré comme un double. Dans un exemple réaliste, les employés peuvent avoir le même nom, nous pouvons donc également souhaiter inclure une comparaison de quelque chose de vraiment unique, comme un identifiant d'employé. Cependant, pour cet exemple simple, nous pouvons simplement trier le nom de l'employé:
Set<Employee> employeeSet = new TreeSet<>(Comparator.comparingInt(Employee::getAge));
Lorsque tous les employés sont ajoutés, le résultat est:
Set<Employee> employeeSet = new TreeSet<>((a,b)->a.getAge()-b.getAge());
" ... ça fait une erreur ... " - Qu'est-ce que ça veut dire? Erreur de compilation? Erreur d'exécution? Mauvais ordre? Veuillez être précis.
@ Turing85 À peu près sûr qu'une erreur de compilation est assez évidente là-bas si le même code est utilisé. Juste une opinion cependant.
@nullpointer oui, c'est évident si vous connaissez les tenants et les aboutissants de l'API Java. Mais tout le monde ne le fait pas. De plus, le site sur le sujet indique clairement que les questions de débogage " doivent inclure [...] un problème spécifique [...] ".
Les HashSets sont des collections non ordonnées.