Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extract a List<D> from a HashMap<E,R> using stream

I want to know how to extract a List<D> from a HashMap<E,R> considering these constraints:

  • E is a custom class;
  • R is a custom class containing a Set<D> of custom objects;

What I have tried: I tried addressing the issue in this question.

In that previous case, I had a simple Map<E,List<R>>, but in this case I have to access the R class which has the targeted Set<D>.

What I want to do in the following portion of the code is to get the Elements of the Set<D> whose country names are equal to the given parameter.

I have tried using the same 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
}
like image 596
Yassine Ben Hamida Avatar asked Jan 07 '19 08:01

Yassine Ben Hamida


People also ask

How do I turn a HashMap into a List?

One way to convert is to use the constructor of the ArrayList. In order to do this, we can use the keySet() method present in the HashMap. This method returns the set containing all the keys of the hashmap.


3 Answers

I believe the flatMap step is wrong, since your map step transforms your Stream<R> to a Stream<Set<D>>, so flatMap(List::stream) should be 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());

Besides, as you can notice above, the code can be much more readable if you avoid using curly braces when you don't have to.

like image 194
Eran Avatar answered Oct 21 '22 14:10

Eran


In order to improve readability of your code I would suggest avoiding unnecessary curly braces in lambdas and even the lambdas themselves. Use method references where possible.

return map.values()
          .stream()
          .map(R::getSet)
          .filter(set -> set.stream()
                            .map(R::getCountry)
                            .anyMatch(countryname::equals))
          .flatMap(Set::stream)
          .collect(toList());

The last flatMap and collect operations can be shortened to one line:

.collect(ArrayList::new, List::addAll, List::addAll); 

Or if you're using Java 9:

.collect(flatMapping(Set::stream, toList()));

However it's just a matter of taste.

like image 4
ETO Avatar answered Oct 21 '22 13:10

ETO


get the Elements of the Set whose country names are equal to the given parameter.

You seem to be looking for

// 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
}
like image 3
Naman Avatar answered Oct 21 '22 13:10

Naman