66

Let's say I have a Dog class.

Inside it I have a Map<String,String> and one of the values is Breed.

public class Dog {
    String id;
    ...
    public Map<String,String>
}

I want to get a Map of Lists:

HashMap<String, List<Dog>> // breed to a List<Dog>

I'd prefer to use a Stream rather than iterating it.

How can I do it?

Eran
  • 387,369
  • 54
  • 702
  • 768
Bick
  • 17,833
  • 52
  • 146
  • 251

3 Answers3

126

You can do it with groupingBy.

Assuming that your input is a List<Dog>, the Map member inside the Dog class is called map, and the Breed is stored for the "Breed" key :

List<Dog> dogs = ...
Map<String, List<Dog>> map = dogs.stream()
     .collect(Collectors.groupingBy(d -> d.map.get("Breed")));
Sergey Nemchinov
  • 1,348
  • 15
  • 21
Eran
  • 387,369
  • 54
  • 702
  • 768
79

The great answer above can further be improved by method reference notation:

List<Dog> dogs = ...
Map<String, List<Dog>> map = dogs.stream()
     .collect(Collectors.groupingBy(Dog::getBreed)); 
Nestor Milyaev
  • 5,845
  • 2
  • 35
  • 51
  • 1
    I guess HashMap should be replaced with Map otherwise IDE with lower project language level will report error. – Sinux Feb 26 '20 at 08:19
2
List<Map<String,Object>> inAppropWords = new ArrayList<>();
    Map<String, Object> s = new HashMap<String, Object>();
    s.put("type", 1);
    s.put("name", "saas");
    Map<String, Object> s1 = new HashMap<String, Object>();
    s1.put("type", 2);
    s1.put("name", "swwaas");
    Map<String, Object> s2 = new HashMap<String, Object>();
    s2.put("type", 1);
    s2.put("name", "saqas");
    inAppropWords.add(s);
    inAppropWords.add(s1);
    inAppropWords.add(s2);
    
    Map<Integer, List<String>> t = inAppropWords.stream().collect(Collectors.groupingBy(d -> AppUtil.getInteger(d.get("type")),Collectors.mapping(d -> String.valueOf(d.get("name")),Collectors.toList())));
    System.out.println(t);