如何递归flatMap流?

时间:2016-05-28 13:30:27

标签: java recursion java-8 java-stream flatmap

我被要求检索作为树节点的descandant的每个叶节点。我很快意识到我可以在一条线上完成这项工作!

public Set<TreeNode<E>> getLeaves() {
    return getChildrenStream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}

第一眼看上去很好,但如果树深达到10,很快会遇到StackOverflowExcepetion,这是我无法接受的。后来我开发了一个没有递归和流的实现(但我的大脑),但是我仍然想知道是否有办法用流做递归flatMap,因为我发现如果不触及流内部,就不可能这样做。它需要一个新的操作系统,例如RecursiveOps,或者我必须在每个步骤中将所有结果收集到Set中,然后对Set进行操作:< / p>

Set<TreeNode<E>> prev = new HashSet<>();
prev.add(this);
while (!prev.isEmpty()) {
    prev = prev.stream().flatMap(n -> n.getChildrenStream()).collect(toSet());
}
return prev;

看起来并不好。流是一个管道。在添加终端操作之前,不会计算其结果和中间结果。上述方法显然违反了这一原则。它也不像溪流那样容易混淆。我可以递归flatMap而无需手动计算所有中间结果吗?

PS1:TreeNode声明:

public class TreeNode<E> {
    // ...
    /**
     * Get a stream of children of the current node. 
     *
     */
    public Stream<TreeNode<E>> getChildrenStream(){
        // ...
    }

    public Set<TreeNode<E>> getLeaves() {
        // main concern
    }
}f

1 个答案:

答案 0 :(得分:0)

不完全确定这是否是您感兴趣的内容:

public static Set<TreeNode<String>> getAllLeaves(TreeNode<String> treeNode) {
    final Stream<TreeNode<String>> childrenStream = treeNode.getChildrenStream();
    if (childrenStream == null) {
        return new HashSet<>();
    }

    Set<TreeNode<String>> ownLeaves = treeNode.getLeaves();
    ownLeaves.addAll(childrenStream.flatMap(stringTreeNode -> getAllLeaves(stringTreeNode).parallelStream())
            .collect(Collectors.toSet()));

    return ownLeaves;
}

开箱即用,我发现这种方法有些不便之处。它确实为最后一次迭代返回一个空集,它正在创建流,就像flatMap一样。但是我相信这是你正在寻找的,因为你正在考虑使用flatMap从你想要的地方获得一个递归创建的连接集,其中首先没有创建流。顺便说一下,我已经尝试过-1000级了,它仍然可以很快地运行,没有问题。