web-dev-qa-db-fra.com

Java 8 re-map avec valeur modifiée

Je suis sur le point de comprendre les nouvelles options Java 8 stream et lambda, mais il y a encore quelques subtilités que je n'ai pas encore pensées.

Disons que j'ai une carte où les clés sont les noms des personnes. La valeur de chaque nom est une carte des âges et des instances Person. Supposons en outre qu'il n'existe pas plus d'une personne portant le même nom et le même âge.

Map<String, NavigableMap<Long, Person>> names2PeopleAges = new HashMap<String, NavigableMap<Long, Person>>();

Après avoir rempli cette carte (ailleurs), je veux produire une autre carte de la personne la plus âgée pour chaque nom. Je veux terminer avec un Map<String, Person> Dans lequel les clés sont identiques à celles de la première carte, mais la valeur de chaque entrée est la valeur de la carte de valeurs pour laquelle la clé de la carte de valeurs a le plus haut nombre.

Profitant du fait qu'un NavigableMap trie ses clés, je peux le faire:

Map<String, Person> oldestPeopleByName = new HashMap<String, Person>();
names2PeopleAges.forEach((name, peopleAges) -> {
  oldestPeopleByName.put(name, peopleAges.lastEntry().getValue());
});

Question: Puis-je remplacer le dernier bit de code ci-dessus par une seule opération Java 8 stream/collect/map/flatten/etc. Pour produire le même résultat? pseudo-code, ma première inclinaison serait:

Map<String, Person> oldestPeopleByName = names2PeopleAges.forEachEntry().mapValue(value->value.lastEntry().getValue());

Cette question est censée être simple, sans astuces ni bizarreries --- juste une simple question de savoir comment je peux pleinement tirer parti de Java 8!

Bonus: Disons que le NavigableMap<Long, Person> Ci-dessus est simplement un Map<Long, Person>. Pourriez-vous étendre la première réponse afin qu'elle recueille la personne ayant la valeur d'âge la plus élevée, maintenant que NavigableMap.lastEntry() n'est pas disponible?

18
Garret Wilson

Vous pouvez créer un flux des entrées et le collecter sur une carte:

Map<String, Person> oldestPeopleByName = 
    names2PeopleAges.entrySet()
                    .stream()
                    .collect (Collectors.toMap(e->e.getKey(),
                                               e->e.getValue().lastEntry().getValue())
                             );

Maintenant, sans lastEntry:

Map<String, Person> oldestPeopleByName = 
    names2PeopleAges.entrySet()
                    .stream()
                    .collect (Collectors.toMap(e->e.getKey(),
                                               e->e.getValue().get(e.getValue().keySet().stream().max(Long::compareTo)))
                             );

Ici, au lieu de compter sur lastEntry, nous recherchons la clé max dans chacun des Maps internes et obtenons la personne correspondante de la clé max.

Je pourrais avoir des fautes de frappe idiotes, car je ne l'ai pas testé, en principe, cela devrait fonctionner.

32
Eran