stream creating List of List (nested List) using forEach, Java 8

  • A+
Category:Languages
class EntityCompositeId {     private Long firstId;     private Long secondId;     // getter & setter... }  class EntityComposite {     private EntityCompositeId id;     private String first;     private String second;     // getter & setter... }  List<EntityComposite> listEntityComposite = .... Supose this content  1, 1, "firstA", "secondBirdOne" 1, 2, "firstA", "secondBirdTwo" 1, 3, "firstA", "secondBirdThree"  2, 1, "firstB", "secondCatOne" 2, 2, "firstB", "secondCatTwo" 2, 3, "firstB", "secondCatThree"  3, 1, "firstC", "secondDogOne" 3, 2, "firstC", "secondDogTwo" 3, 3, "firstC", "secondDogThree"  Map<Long, List<String>> listOfLists = new HashMap<>(); 

Now using stream I want to fill like:

 1 -> {"secondBirdOne", "secondBirdTwo", "secondBirdThree"}  2 -> {"secondCatOne", "secondCatTwo", "secondCatThree"}  3 -> {"secondDogOne", "secondDogTwo", "secondDogThree"} 

My UNFINISHED (that's the question) code is:

listEntityComposite.stream()forEach(entityComposite {         // How create a list according entityComposite.getId.getFirstId()?         listOfLists.put(entityComposite.getId.getFirstId(), .... )     }); 

 


There are several different approaches in which you can accomplish the task at hand.

forEach + computeIfAbsent

 Map<Long, List<String>> map = new HashMap<>();  listEntityComposite.forEach(e -> map.computeIfAbsent(e.getId().getFirstId(),                  k -> new ArrayList<>()).add(e.getSecond())); 
  • enumerates over the elements in listEntityComposite via forEach
  • for each element utilises computeIfAbsent to compute the key (i.e. firstId) and value (i.e. List<String>)

groupingBy + mapping

another approach would be to apply a groupingBy with a mapping downstream collector:

Map<Long, List<String>> resultSet = listEntityComposite.stream()                 .collect(groupingBy(e -> e.getId().getFirstId(),                         mapping(EntityComposite::getSecond, toList()))); 
  • groups the source elements by the classification function e.getId().getFirstId() and then applies a mapping downstream collector to further refine our query.

forEach + merge

listEntityComposite.forEach(e -> map.merge(e.getId().getFirstId(),                 new ArrayList<>(singletonList(e.getSecond())),                 (l, r) -> {l.addAll(r); return l;})); 
  • enumerates over the elements in listEntityComposite via forEach

  • for each element utilises merge to compute the key (i.e. firstId) and value (i.e. List<String>)

toMap

listEntityComposite.stream()                    .collect(toMap(e -> e.getId().getFirstId(),                               v ->  new ArrayList<>(singletonList(v.getSecond())),                              (l, r) -> {l.addAll(r); return l;})); 
  • applies a keyMapper function e -> e.getId().getFirstId() to extract the map keys.
  • applies a valueMapper function v -> new ArrayList<>(singletonList(v.getSecond())) to extract the map values.
  • applies a merge function (l, r) -> {l.addAll(r); return l;} to resolve key collisions.

To conclude, the forEach + computeIfAbsent approach and the groupingBy + mapping approach are the two you should favour in this specific case as they're the more idiomatic.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: