Java 8 使用流和收集器映射到集合的子列表条目
Java 8 mapping to sub list entries of a collection using streams and collectors
我收集了 Person
个对象:.
public class Person {
String name;
ChildrenListHolder childrenListHolder;
}
public class ChildrenListHolder {
List<Children> children;
}
public class Children {
String childrensName;
}
(实体结构由第三方给出。)
现在,我需要一个 Map<String,List<Person>>
childrensName -> person-list
例如(简体):
Person father: {name: "John", childrensListHolder -> {"Lisa", "Jimmy"}}
Person mother: {name: "Clara", childrensListHolder -> {"Lisa", "Paul"}}
Person george: {name: "George", childrensListHold -> "Paul"}}
地图,我需要的是
Map<String, List<Person>> map: {"Lisa" -> {father, mother},
"Jimmy" -> {father},
"Paul" -> {mother, george}}
我可以用一堆 for 和 if 来做到这一点。但是我如何使用流和收集器来做到这一点。我尝试了很多方法,但我无法得到预期的结果。 TIA.
给定一个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())
));
这是在人身上创建一个流。然后每个人都由一个包含 child 的元组和每个 child 对应的人进行平面映射。最后,我们按 child 姓名分组并将所有人员收集到一个列表中。
假设有合适的构造函数的示例代码:
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.
我知道您要求 stream/collectors 解决方案,但无论如何,使用 Map#computeIfAbsent
的嵌套 for 循环也能正常工作:
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);
}
}
并且这是使用集合中引入的新 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)));
当然,它不像 Tunaki 的解决方案 (+1) 那样是单行的,也不是容易并行化的,但是您也不需要 "bunch" of if's 来实现它(并且您也避免了创建临时映射条目实例)。
我收集了 Person
个对象:.
public class Person {
String name;
ChildrenListHolder childrenListHolder;
}
public class ChildrenListHolder {
List<Children> children;
}
public class Children {
String childrensName;
}
(实体结构由第三方给出。)
现在,我需要一个 Map<String,List<Person>>
childrensName -> person-list
例如(简体):
Person father: {name: "John", childrensListHolder -> {"Lisa", "Jimmy"}}
Person mother: {name: "Clara", childrensListHolder -> {"Lisa", "Paul"}}
Person george: {name: "George", childrensListHold -> "Paul"}}
地图,我需要的是
Map<String, List<Person>> map: {"Lisa" -> {father, mother},
"Jimmy" -> {father},
"Paul" -> {mother, george}}
我可以用一堆 for 和 if 来做到这一点。但是我如何使用流和收集器来做到这一点。我尝试了很多方法,但我无法得到预期的结果。 TIA.
给定一个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())
));
这是在人身上创建一个流。然后每个人都由一个包含 child 的元组和每个 child 对应的人进行平面映射。最后,我们按 child 姓名分组并将所有人员收集到一个列表中。
假设有合适的构造函数的示例代码:
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.
我知道您要求 stream/collectors 解决方案,但无论如何,使用 Map#computeIfAbsent
的嵌套 for 循环也能正常工作:
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);
}
}
并且这是使用集合中引入的新 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)));
当然,它不像 Tunaki 的解决方案 (+1) 那样是单行的,也不是容易并行化的,但是您也不需要 "bunch" of if's 来实现它(并且您也避免了创建临时映射条目实例)。