web-dev-qa-db-fra.com

Filtre de Java 8 Strem dans la carte - Carte <String, Carte <String, Employé >>

Comment filtrer un Map<String,Map<String,Employee>> en utilisant Java 8 Filter?

Je dois filtrer uniquement lorsqu'un employé de la liste a une valeur de champ Gender = "M".

Contribution: 

Map<String,Map<String,Employee>>

Sortie: 

Map<String,Map<String,Employee>>

Critères de filtrage: 

Employee.genter = "M"

De plus, je dois retourner une carte vide si le résultat filtré est vide.

J'ai essayé le ci-dessous, mais cela ne fonctionne pas comme prévu. Il retourne le seul si tous les employés sont avec le sexe "M".

tempCollection.entrySet().stream()
                        .filter(i -> i.getValue().entrySet().stream().allMatch(e-> "M".equals(e.getValue().getGender())))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
5
user1578872

Vous pouvez simplement itérer sur les paires clé-valeur et filtrer comme suit:

Map<String, Map<String, Employee>> output = new HashMap<>();
tempCollection.forEach((k, v) -> {
    if (v.values().stream().anyMatch(i -> "M".equals(i.getGender()))) {
        output.put(k, v.entrySet()
                .stream()
                .filter(i -> "M".equals(i.getValue().getGender()))
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)));
    }
});
1
nullpointer

On dirait que ce que vous cherchez est donné un Entry<String,Map<String,Employee>> s'il y a un employé qui a un sexe de "M" puis filtrez le Map<String,Employee> intérieur pour ne contenir que les entrées avec un genre "M".

dans ce cas, vous pouvez filter avec anyMatch pour le premier critère. De plus, lors de la phase de collecte, vous pouvez appliquer le filtrage sur la carte interne:

tempCollection.entrySet().stream()
            .filter(i -> i.getValue().values().stream().anyMatch(e -> "M".equals(e.getGender())))
            .collect(toMap(Map.Entry::getKey,
                    v -> v.getValue().entrySet().stream()
                            .filter(i -> "M".equals(i.getValue().getGender()))
                            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))));
1
Aomine

La fonction allMatch ne correspond que si chaque élément du flux correspond au prédicat; vous pouvez utiliser anyMatch pour faire correspondre si un élément correspond au prédicat:

tempCollection.entrySet().stream()
                        .filter(i -> i.getValue().entrySet().stream().anyMatch(e-> "M".equals(e.getValue().getGender())))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
1
Tordek

Vous pouvez le faire comme ça,

Map<String, Map<String, Employee>> maleEmpMap = tempCollection.entrySet().stream()
    .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(),
        e.getValue().entrySet().stream().filter(emp -> "M".equals(emp.getValue().getGender()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Prenez chaque entrée de carte de la carte externe et créez une nouvelle entrée de carte en utilisant la même clé et la carte imbriquée nouvellement construite avec la même clé et comportant uniquement des employés de sexe masculin. Enfin, collectez toutes les entrées correspondantes dans une nouvelle carte externe. Ceci gérera gracieusement le scénario vide que vous avez mentionné dans la déclaration de problème ci-dessus.

1
Ravindra Ranwala

Une autre façon serait comme ça: 

map.values()
     .removeIf(entry->entry.values().stream().anyMatch(e -> !"M".equals(e.getGender())));

map.entrySet()
    .removeIf(entry->entry.getValue().size() == 0);
0
Hadi J