Je veux savoir comment extraire une List
d'une HashMap
en tenant compte de ces contraintes:
E
est une classe personnalisée; R
est une classe personnalisée contenant un Set
d'objets personnalisés; Ce que j'ai essayé: j'ai essayé de résoudre le problème dans cette question .
Dans ce cas précédent, j'avais une simple Map
, mais dans ce cas j'ai pour accéder à la classe R
qui a le Set
ciblé .
Ce que je veux faire dans la partie suivante du code est d'obtenir les éléments du Set
dont les noms de pays sont égaux au paramètre donné.
J'ai essayé d'utiliser la même solution:
Map<E,R> map = new HashMap<E,R>(); public List<D> method(String countryname) { return map.values().stream().filter((x)->{ return x.getSet().stream().anyMatch((t) -> { return t.getCountry().equals(countryname); }); }) .map(R::getSet) .flatMap(List::stream) .collect(Collectors.toList()); //does not compile } // the R class class R { private Set<D> set = new TreeSet<D>(); //getters & setters & other attributes }
3 Réponses :
Je pense que l'étape flatMap
est erronée, car votre étape map
transforme votre Stream
en un Stream
, donc flatMap (List :: stream)
doit être flatMap (Set :: stream)
:
return map.values() .stream() .filter(x -> x.getSet().stream().anyMatch(t -> t.getCountry().equals(countryname))) .map(R::getSet) .flatMap(Set::stream) .collect(Collectors.toList());
De plus, comme vous pouvez le remarquer ci-dessus, le code peut être beaucoup plus lisible si vous évitez d'utiliser des accolades lorsque vous n'en avez pas besoin.
Un problème qui pourrait être évité en utilisant simplement Collection :: stream
ou en remplaçant les deux étapes .map (R :: getSet) .flatMap (Set :: stream)
par un .flatMap (r -> r.getSet (). stream ())
…
@nullpointer en supposant que getSet ()
retourne toujours le même ensemble ou un ensemble équivalent, le code de l'OP et cette solution incluront tous les éléments de tous les ensembles contenant au moins un élément correspondant, alors que votre solution ne contiendra que les éléments correspondants.
récupère les éléments de l'ensemble dont les noms de pays sont égaux au paramètre.
Vous semblez rechercher
// input as parameter to the method for simplicity public List<D> method(Map<E, R> map, String countryName) { return map.values() // Collection<R> .stream() // Stream<R> .flatMap(a -> a.getSet().stream()) // Stream<D> .filter(t -> t.getCountry().equals(countryName)) // filtered .collect(Collectors.toList()); // collected to list }
Les deux solutions affichées dans les deux réponses ne sont pas équivalentes. J'ai corrigé l'erreur dans la tentative des OP, sans changer leur logique, car j'ai supposé que c'était ce qu'ils voulaient. Seul l'OP peut dire laquelle des deux options correspond à ce qu'il souhaite.
@Eran En effet, c'est ce que je me demandais pour le anyMatch
dans votre solution. Laissant cela à l'OP alors. Merci encore. :)
Afin d'améliorer la lisibilité de votre code, je suggère d'éviter les accolades inutiles dans les lambdas et même les lambdas eux-mêmes. Utilisez des références de méthode lorsque cela est possible.
.collect(flatMapping(Set::stream, toList()));
Les dernières opérations flatMap
et collect
peuvent être raccourcies à une ligne:
.collect(ArrayList::new, List::addAll, List::addAll);
Ou si vous utilisez Java 9:
return map.values() .stream() .map(R::getSet) .filter(set -> set.stream() .map(R::getCountry) .anyMatch(countryname::equals)) .flatMap(Set::stream) .collect(toList());
Cependant, c'est juste une question de goût.
@nullpointer Juste au cas où vous ne le sauriez pas, l'OP reçoit déjà une notification lorsque vous postez une réponse à sa question. Il n'est pas nécessaire de publier un commentaire avec un lien vers la réponse.
Comme Holger l'a également souligné dans un commentaire, l'utilisation de la solution que j'avais suggérée à la question liée aurait pu éviter cela échec. c'est-à-dire en utilisant
Collection :: stream