【发布时间】:2021-06-25 23:36:48
【问题描述】:
我有一个列表:List<XNode> nodes,每个XNode 都有一个ArrayList<XNode> children; 和int id; 作为成员变量。如何在 java 中创建我所有节点的Map<ParentId, ChildId>?
【问题讨论】:
标签: java list recursion java-stream
我有一个列表:List<XNode> nodes,每个XNode 都有一个ArrayList<XNode> children; 和int id; 作为成员变量。如何在 java 中创建我所有节点的Map<ParentId, ChildId>?
【问题讨论】:
标签: java list recursion java-stream
首先,如果每个节点中有一个 list 子节点,则不可能为每个 childId 创建一个 parentId 的 map,因为通常情况下是 parentId键可能有多个childId 值,必须以某种方式解决此冲突。
因此,可以创建 Map<Integer, List<Integer>>,其中 List<Integer> 包含所有孩子的 id,或者创建 List<List<Integer>>(其中内部 List<Integer> 包含一对 parentId 和 childId)。
最后,需要定义结果是包含roots还是leafs。
区别可以描述为:根有它们的parentId = null和非空childId,叶子总是有非空parentId而childId可能是null.
假设输入节点列表是这样定义的:
List<XNode> list = Arrays.asList(
new XNode(1, Arrays.asList(new XNode(11, Arrays.asList(new XNode(111), new XNode(112))), new XNode(12), new XNode(13))),
new XNode(2),
new XNode(3, Arrays.asList(new XNode(31, Arrays.asList(new XNode(311)))))
);
那么地图可以如下创建:
Map<Integer, List<Integer>> map = list.stream()
.flatMap(Main::flatMapEntry)
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new
));
System.out.println("map example: " + map);
使用递归方法flatMapEntry:
static Stream<Map.Entry<Integer, List<Integer>>> flatMapEntry(XNode node) {
return node.getChildren().isEmpty()
? Stream.of(Map.entry(node.getId(), Collections.emptyList()))
: Stream.concat(
Stream.of(Map.entry(
node.getId(),
node.getChildren().stream()
.map(XNode::getId)
.collect(Collectors.toList())
)),
node.getChildren().stream().flatMap(Main::flatMapEntry)
);
}
给定输入的输出(10 个键,13 个值):
地图示例:{1=[11, 12, 13], 11=[111, 112], 111=[], 112=[], 12=[], 13=[], 2=[], 3=[31], 31=[311], 311=[]}
构建对列表的示例:
List<XNode>:List<List<Integer>> leafsBreadth = flatList(list).collect(Collectors.toList());
System.out.println("leafs(breadth): " + leafsBreadth.size() + ": " + leafsBreadth);
// ---
static Stream<List<Integer>> flatList(List<XNode> list) {
return list.stream()
.flatMap(x -> x.getChildren().isEmpty()
? Stream.of(Arrays.asList(x.getId(), null))
: Stream.concat(x.getChildren().stream()
.map(c -> Arrays.asList(x.getId(), c.getId())),
flatList(x.getChildren())
));
}
输出:
叶子(宽度):13:[[1, 11], [1, 12], [1, 13], [11, 111], [11, 112], [111, null], [112, null], [12, null], [13, null], [2, null], [3, 31], [31, 311], [311, null]]
List<XNode>(列表中的每个XNode):List<List<Integer>> leafsDepth = list.stream()
.flatMap(x -> flatChildren(x)).collect(Collectors.toList());
System.out.println("leafs(depth): " + leafsDepth.size() + ": " + leafsDepth);
// ----
static Stream<List<Integer>> flatChildren(XNode node) {
return node.getChildren().isEmpty()
? Stream.of(Arrays.asList(node.getId(), null))
: node.getChildren().stream().flatMap(x -> Stream.concat(
Stream.of(Arrays.asList(node.getId(), x.getId())),
flatChildren(x)
));
}
输出:
叶子(深度):13:[[1, 11], [11, 111], [111, null], [11, 112], [112, null], [1, 12], [12, null], [1, 13], [13, null], [2, null], [3, 31], [31, 311], [311, null]]
List<List<Integer>> rootsDepth = list.stream()
.flatMap(x -> flatRoots(null, x)) // using null for missing parentId
.collect(Collectors.toList());
System.out.println("roots(depth): " + rootsDepth.size() + ": " + rootsDepth);
// ----
static Stream<List<Integer>> flatRoots(Integer parentId, XNode node) {
return Stream.concat(
Stream.of(Arrays.asList(parentId, node.getId())),
node.getChildren().stream().flatMap(x -> flatRoots(node.getId(), x))
);
}
输出:
根(深度): 10: [[null, 1], [1, 11], [11, 111], [11, 112], [1, 12], [1, 13], [null, 2], [null, 3], [3, 31], [31, 311]]
【讨论】: