2017-05-25 230 views
2

如果可能在一个班轮中使用Java 8流汇总树的节点,有可能吗?使用Java 8 Streams汇总树节点

这里是一个节点类来解决,这是使用一个递归和总结节点,如以下代码

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(); 
    } 
} 

我们可以使用流来概括眼前的子节点,但我没有得到如何将深使用流做递归。 此代码仅将问题解决到单个级别。有任何想法吗?

total = list.stream().filter(Node -> node.children.isEmpty()).map(Node:: getNodeNum).reduce(node.getNodeNum(), (a,b) -> a+b); 

回答

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.mapToIntIntStream.sum方法一起来计算总和。


或者,你可以在你的NodeFunction<Node, Stream<Node>> descendants属性执行到位递归:

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表达式分配给局部变量。

public Stream<Node> allChildren() { 
    return descendants.apply(this); 
} 

最后,您getNodeSum方法的代码可以等同于以前的版本:

int getNodeSum(Node node) { 
    return node.allChildren() 
     .mapToInt(Node::getNodeNum) 
     .sum(); 
} 

有了递归函数,可以按如下方式重写allChildren方法注意:虽然这种方法可能对某些人有吸引力,但它可能有一些缺点,即现在每个Node类的实例都具有descendants属性,尽管不需要二。你可以绕过这个,即通过使用这个递归函数的Tree类作为属性,并且Node是内部类(其中descendants属性被移除)。

1

您需要添加节点类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());