[英]Java 8 mapping to sub list entries of a collection using streams and collectors
I have a collection of Person
objects:. 我有一个Person
对象的集合:
public class Person {
String name;
ChildrenListHolder childrenListHolder;
}
public class ChildrenListHolder {
List<Children> children;
}
public class Children {
String childrensName;
}
(The entity structure is given by third party.) (实体结构由第三方提供。)
Now, I need a Map<String,List<Person>>
childrensName -> person-list 现在,我需要一个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"}}
The map, I need is 我需要的地图是
Map<String, List<Person>> map: {"Lisa" -> {father, mother},
"Jimmy" -> {father},
"Paul" -> {mother, george}}
I can do that with a bunch of for's and if's. 我可以用一堆for和if来做到这一点。 But how can I do this using streams and collectors. 但是我如何使用流和收集器来做到这一点。 I have tried many approaches, but I cannot get the expected result. 我尝试了很多方法,但是我无法得到预期的结果。 TIA. TIA。
Given a List<Person> persons
, you can have the following 给定List<Person> persons
,您可以拥有以下内容
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 is creating a Stream over the persons. 这正在为人们创造一条流。 Then each person is flat mapped by a tuple holding the child and the person for each child. 然后每个人通过一个元组来平面映射,该元组持有孩子和每个孩子的人。 Finally, we group by the child name and collect all the persons into a list. 最后,我们按子名称分组并将所有人员收集到一个列表中。
Sample code assuming there are 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);
}
I can do that with a bunch of for's and if's. 我可以用一堆for和if来做到这一点。
I know that you asked for a stream/collectors solution, but in any case a nested for loop using Map#computeIfAbsent
works fine too: 我知道你要求一个流/收集器解决方案,但无论如何使用Map#computeIfAbsent
的嵌套for循环也可以Map#computeIfAbsent
工作:
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 written using the new forEach
method introduced on collections: 这是使用集合中引入的新forEach
方法编写的:
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 it's not a one-liner nor easy parallelizable like in Tunaki's solution (+1), but you don't need a "bunch" of if's to achieve that too (and you avoid also the creation of temporary map entries instances). 当然,它不是单线程,也不像Tunaki的解决方案(+1)那样易于并行化,但是你也不需要“束”来实现它(并且你也避免创建临时的映射条目实例)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.