是否可以使用Java 8流来汇总树的节点,如果可能的话,可以在一个班轮中使用?
这是一个节点类
public class Node
{
private int nodeNum;
ArrayList<Node> children = new ArrayList<>();
public Node(int num)
{
this.nodeNum = num;
}
public int getNodeNum()
{
return nodeNum;
}
public boolean addNode(Node node)
{
return children.add(node);
}
public ArrayList<Node> getNodes()
{
return this.children;
}
}
解决这个问题的正常方法是使用递归并总结节点,如下面的代码。
int getNodeSum(Node node)
{
int total = 0;
if(node.children.isEmpty())
return node.getNodeNum();
else
{
for(Node tempNode:node.children)
{
total+= getNodeSum(tempNode);
}
return total+node.getNodeNum();
}
}
我们可以使用流来总结直接子节点,但我没有得到如何深入移动并使用Streams递归执行。 此代码仅将问题解决到单个级别。有什么想法吗?
total = list.stream().filter(Node -> node.children.isEmpty()).map(Node:: getNodeNum).reduce(node.getNodeNum(), (a,b) -> a+b);
答案 0 :(得分:3)
您的问题的一个解决方案是使用递归和Stream.flatMap
。
首先,您需要将以下帮助方法添加到Node
类:
public Stream<Node> allChildren() {
return Stream.concat(
Stream.of(this),
this.children.stream().flatMap(Node::allChildren)); // recursion here
}
返回Stream<Node>
,其元素是此节点及其所有后代节点。
然后,您可以按如下方式重写getNodeSum
方法:
int getNodeSum(Node node) {
return node.allChildren()
.mapToInt(Node::getNodeNum)
.sum();
}
这使用上面定义的Node.allChildren
方法以及Stream.mapToInt
和IntStream.sum
方法来计算总和。
或者,您可以在Function<Node, Stream<Node>> descendants
类中使用Node
属性来执行递归:
private Function<Node, Stream<Node>> descendants =
node -> Stream.concat(
Stream.of(node),
node.children.stream()
.flatMap(this.descendants)); // recursion here: function invoked again
这是递归lambda表达式,因为您定义的函数位于=
符号的两侧。这种lambda表达式只允许作为类的属性,即你不能将递归的lambda表达式赋给局部变量。
使用该递归函数,您可以按如下方式重写allChildren
方法:
public Stream<Node> allChildren() {
return descendants.apply(this);
}
最后,您的getNodeSum
方法的代码与之前的版本相同:
int getNodeSum(Node node) {
return node.allChildren()
.mapToInt(Node::getNodeNum)
.sum();
}
注意:虽然这种方法可能对某些人有吸引力,但它可能有一些缺点,即现在Node
类的每个实例都具有descendants
属性,尽管根本不需要。您可以通过使用此Tree
类将此递归函数作为属性来绕过这一点,并且Node
是内部类(删除了descendants
属性)。
答案 1 :(得分:1)
您需要为Node类添加recusive方法,它将加入子流
public Stream<Node> recursiveConcat() {
return Stream.concat(
Stream.of(this),
children.stream().flatMap(Node::recursiveConcat));
}
然后做 -
root.recusiveConcat().mapToInt(Node::getNodeNum).sum()
整个代码
public class Node {
private int nodeNum;
ArrayList<Node> children = new ArrayList<>();
public Node(int num) {
this.nodeNum = num;
}
public int getNodeNum() {
return nodeNum;
}
public boolean addNode(Node node) {
return children.add(node);
}
public ArrayList<Node> getNodes() {
return this.children;
}
public Stream<Node> recursiveConcat() {
return Stream.concat(
Stream.of(this),
children.stream().flatMap(Node::recursiveConcat));
}
}
Node root = new Node(1);
Node node1 = new Node(2);
Node node2 = new Node(3);
Node node3 = new Node(4);
node2.addNode(node3);
node1.addNode(node2);
root.addNode(node1);
System.out.println(root.recursiveConcat().mapToInt(Node::getNodeNum).sum());