J'ai une structure de données qui est comme ci-dessous:
new StudentDetails(id: 36, studentStatus: StudentStatus.PHD, name: "Anil");
Que je peux appeler pour un statut d'étudiant comme PHD, et cela me donnera un TreeMap of Integer to Student objets. Cette TreeMap
contient les identifiants d'étudiant comme clés et les objets Student comme valeurs.
public enum StudentStatus { UNDERGRAD, POSTGRAD, PHD; } public class Student { public String name; public int age; } public class StudentDetails { public int id; public StudentStatus studentStatus; public String name; }
Maintenant, ce que je veux faire, c'est obtenir le plus jeune élève en age, en d'autres termes, recherchez la carte imbriquée et créez un objet StudentDetails à partir de cet étudiant. J'aurai donc besoin des clés des 2 premières cartes. La première clé est StudentStatus, et la deuxième clé est l'identifiant de l'étudiant.
À la fin, j'aurai besoin d'un objet comme celui-ci:
Map<StudentStatus, TreeMap<Integer, Student>> map = new HashMap<>();
I impossible de trouver un moyen de stocker ces clés pendant le streaming et de créer l'objet final avec Java 8 Stream en une seule instruction.
J'ai simplifié le problème avec l'analogie de Student, peut-être que cela n'a pas beaucoup de sens de utiliser une telle structure pour le problème ci-dessus, mais dans mon cas, c'est le cas.
3 Réponses :
Cette alternative utilise un Collector au minimum; pas de tri, le runtime est en O (n).
var student = map.values().stream() .flatMap(m -> m.entrySet().stream()) .map(Map.Entry::getValue) .collect(Collectors.minBy(Student::getAge)) .get();
Il renvoie l'objet Student au lieu de StudentDetails.
Construisez Map.Entry
avec l'âge comme clé et StudentDetails
comme valeur. Ensuite, triez-le et obtenez en premier.
.min(Comparator.comparingInt(Map.Entry::getKey)) .map(Map.Entry::getValue) .get();
Comme il a été écrit dans le commentaire ci-dessous: la dernière partie (de 'trié') peut être remplacé par le code ci-dessous:
StudentDetails studentDetails = map.entrySet().stream() .flatMap(statusEntry -> statusEntry.getValue().entrySet().stream() .map(ageEntry -> new AbstractMap.SimpleEntry<Integer, StudentDetails>( ageEntry.getValue().getAge(), new StudentDetails( ageEntry.getKey(), statusEntry.getKey(), ageEntry.getValue().getName()))) ).sorted(Comparator.comparingInt(Map.Entry::getKey)) .findFirst() .map(Map.Entry::getValue) .get();
Une combinaison de sort (). FindFirst ()
peut être facilement remplacée par min
ou max
Si vous recherchez un StudentDetails
correspondant à un StudentStatus
, vous pouvez utiliser le Stream # min
tel que:
Map<StudentStatus, StudentDetails> statusToYoungestStudentDetail(Map<StudentStatus, TreeMap<Integer, Student>> map, StudentStatus studentStatus) { return map.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().entrySet() .stream() .min(Comparator.comparing(en -> en.getValue().getAge())) .map(entry -> new StudentDetails(entry.getKey(), studentStatus, entry.getValue().getName())) .orElseThrow(IllegalArgumentException::new))); }
De même, si vous recherchiez les détails de chaque élève le plus jeune basé sur le statut, vous pouvez utiliser:
StudentDetails detailsForGivenStatus(Map<StudentStatus, TreeMap<Integer, Student>> map, StudentStatus studentStatus) { return map.get(studentStatus).entrySet().stream() .min(Comparator.comparing(e -> e.getValue().getAge())) .map(entry -> new StudentDetails(entry.getKey(), studentStatus, entry.getValue().getName())) .orElseThrow(IllegalArgumentException::new); }
StudentEnum
ouStudentStatus
?Je viens de le réparer. Merci.
Pouvez-vous ajouter l'âge des élèves à la classe
StudentDetails
en tant que membre?