Java 8 mapping for entries in collection subtitles using streams and collectors

I have a collection of Person : objects.

 public class Person { String name; ChildrenListHolder childrenListHolder; } public class ChildrenListHolder { List<Children> children; } public class Children { String childrensName; } 

(The entity structure is provided by a third party.)

Now I need Map<String,List<Person>> childrensName → person-list

For example (simplified):

 Person father: {name: "John", childrensListHolder -> {"Lisa", "Jimmy"}} Person mother: {name: "Clara", childrensListHolder -> {"Lisa", "Paul"}} Person george: {name: "George", childrensListHold -> "Paul"}} 

I need a card

 Map<String, List<Person>> map: {"Lisa" -> {father, mother}, "Jimmy" -> {father}, "Paul" -> {mother, george}} 

I can do this with a bunch for and if. But how can I do this using streams and collectors. I have tried many approaches, but I cannot get the expected result. TIA.

+5
source share
2 answers

Given List<Person> persons , you can have the following

 Map<String,List<Person>> map = persons.stream() .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p))) .collect(Collectors.groupingBy( e -> e.getKey().childrensName, Collectors.mapping(Map.Entry::getValue, Collectors.toList()) )); 

This creates a stream over people. Then each person is densely displayed on the motorcade, holding the child and the person for each child. Finally, we group the name of the child and put all the people on the list.

Sample code assuming appropriate constructors:

 public static void main(String[] args) { List<Person> persons = Arrays.asList( new Person("John", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Jimmy")))), new Person("Clara", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Paul")))), new Person("George", new ChildrenListHolder(Arrays.asList(new Children("Paul")))) ); Map<String,List<Person>> map = persons.stream() .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p))) .collect(Collectors.groupingBy( e -> e.getKey().childrensName, Collectors.mapping(Map.Entry::getValue, Collectors.toList()) )); System.out.println(map); } 
+7
source

I can do this with a bunch for and if.

I know that you asked for a solution for stream / collectors, but in any case, a loop of nested loops using Map#computeIfAbsent works fine too:

 Map<String, List<Person>> map = new HashMap<>(); for(Person p : persons) { for(Children c : p.childrenListHolder.children) { map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p); } } 

and this is written using the new forEach method introduced in the collection:

 Map<String, List<Person>> map = new HashMap<>(); persons.forEach(p -> p.childrenListHolder.children.forEach(c -> map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p))); 

Of course, this is not single-line or simple parallelizable, as in the Tunaki (+1) solution, but you do not need a bunch if for this too (and you also avoid creating temporary map records for instances).

+5
source

Source: https://habr.com/ru/post/1245939/


All Articles