web-dev-qa-db-fra.com

Java 8 extrait toutes les clés des valeurs correspondantes dans une carte

Je suis relativement nouveau sur Java8 et, dans un scénario, je dois récupérer toutes les clés de la carte qui correspondent aux objets. 

Je voulais savoir s’il existait un moyen d’obtenir toutes les clés sans les réitérer de la liste. 

Person.Java
private String firstName;
private String lastName;
//setters and getters & constructor


MAIN Class.

String inputCriteriaFirstName = "john";   

Map<String, Person> inputMap = new HashMap<>();
Collection<Person> personCollection = inputMap.values();
List<Person> personList = new ArrayList<>(personCollection);
List<Person> personOutputList = personList.stream()
.filter(p -> p.getFirstName().contains(inputCriteriaFirstName ))
.collect(Collectors.toList());


//IS There a BETTER way to DO Below ??

Set<String> keys = new HashSet<>();
for(Person person : personOutputList) {
    keys.addAll(inputMap.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), person))
        .map(Map.Entry::getKey).collect(Collectors.toSet()));
}
10
Srinivas Lakshman
inputMap.entrySet() 
        .stream()
        .filter(entry -> personOutputList.contains(entry.getValue()))
        .map(Entry::getKey)
        .collect(Collectors.toCollection(HashSet::new))
8
Eugene

Vous pouvez également utiliser foreach api fourni dans Java8 sous lambda

Ci-dessous le code de votre méthode principale: 

public static  void main() {

        String inputCriteriaFirstName = "john";   

        Map<String, Person> inputMap = new HashMap<>();
        Set<String> keys = new HashSet<>();

        inputMap.forEach((key,value) -> {
            if(value.getFirstName().contains(inputCriteriaFirstName)){
                keys.add(key);
            }
        });
    }
6
Sahil Aggarwal

Au lieu de parcourir toutes les entrées de la carte pour chaque Person, je suggère de parcourir une fois la carte:

Set<String> keys =
     inputMap.entrySet()
             .stream()
             .filter(e -> personOutputList.contains(e.getValue()))
             .map(Map.Entry::getKey)
             .collect(Collectors.toCollection(HashSet::new));

Cela entraînerait toujours un temps d'exécution quadratique (puisque List.contains() a un temps d'exécution linéaire). Vous pouvez améliorer le temps de fonctionnement linéaire global si vous créez une HashSet contenant les éléments de personOutputList, car contains pour HashSet prend un temps constant.

Vous pouvez y parvenir en changeant

List<Person> personOutputList = 
    personList.stream()
              .filter(p -> p.getFirstName().contains(inputCriteriaFirstName))
              .collect(Collectors.toList());

à

Set<Person> personOutputSet = 
    personList.stream()
              .filter(p -> p.getFirstName().contains(inputCriteriaFirstName))
              .collect(Collectors.toCollection(HashSet::new));
5
Eran

Donc, vous voulez une personOutputList avec toutes les personnes sélectionnées et un keys avec les clés pour ces personnes sélectionnées?

La meilleure option (pour les performances) est de ne pas ignorer les clés lors de la recherche, puis de diviser le résultat en une liste de personnes et un jeu de clés distincts.

Comme ça:

String inputCriteriaFirstName = "john";
Map<String, Person> inputMap = new HashMap<>();

Map<String, Person> tempMap = inputMap.entrySet()
        .stream()
        .filter(e -> e.getValue().getFirstName().contains(inputCriteriaFirstName))
        .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
List<Person> personOutputList = new ArrayList<>(tempMap.values());
Set<String> keys = new HashSet<>(tempMap.keySet());

L'ensemble keys est explicitement transformé en une copie pouvant être mise à jour. Si vous n'en avez pas besoin, supprimez la copie des valeurs de clé:

Set<String> keys = tempMap.keySet();
1
Andreas