1
votes

Rechercher un élément min / max dans une carte imbriquée avec l'API Java 8 Stream

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 commentaires

StudentEnum ou StudentStatus ?


Je viens de le réparer. Merci.


Pouvez-vous ajouter l'âge des élèves à la classe StudentDetails en tant que membre?


3 Réponses :


0
votes

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


1 commentaires

Il renvoie l'objet Student au lieu de StudentDetails.



1
votes

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

MISE À JOUR

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


1 commentaires

Une combinaison de sort (). FindFirst () peut être facilement remplacée par min ou max



1
votes

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


0 commentaires