8
votes

Comment extraire une liste d'un HashMap à l'aide d'un flux

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
}


2 commentaires

@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


3 Réponses :


5
votes

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.


2 commentaires

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.



3
votes

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
}

2 commentaires

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. :)



4
votes

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.


0 commentaires