用parallelStream替换for循环 - Java

时间:2022-12-13 20:59:18

I have the following method that calls itself recursively:

我有以下方法递归调用自身:

public ArrayList<SpecTreeNode> getLeavesBelow()
   {
      ArrayList<SpecTreeNode> result = new ArrayList<>();
      if (isLeaf())
      {
         result.add(this);
      }

      for (SpecTreeNode stn : chList)
      {
         result.addAll(stn.getLeavesBelow());
      }
      return result;
   }

I'd like to convert the for loop to use parallelStream. I think I'm partly there but not sure how to implement .collect() to 'addAll' to result:

我想将for循环转换为使用parallelStream。我想我部分在那里,但不确定如何实现.collect()到'addAll'到结果:

chList.parallelStream()
             .map(SpecTreeNode::getLeavesBelow)
             .collect();

Some assistance would be much appreciated.

一些援助将不胜感激。

2 个解决方案

#1


1  

Just like this, right? Am I missing something?

就像这样,对吗?我错过了什么吗?

result.addAll(
    chList.parallelStream()
         .map(SpecTreeNode::getLeavesBelow)
         .flatMap(Collection::stream)
         .collect(Collectors.toList())
);

Unrelated to your question but because you're seeking performance improvements: you may see some gains by specifying an initial size for your ArrayList to avoid reallocating multiple times.

与您的问题无关,但是因为您正在寻求性能改进:您可以通过指定ArrayList的初始大小来避免多次重新分配,从而获得一些收益。

A LinkedList may be a preferable data structure if you can't anticipate the size, as all you're doing here is continually appending to the end of the list. However, if you need to randomly access elements of this list later then it might not be.

如果你无法预测大小,LinkedList可能是一个更好的数据结构,因为你在这里所做的只是不断追加到列表的末尾。但是,如果您需要稍后随机访问此列表的元素,则可能不会。

#2


1  

I would do it by making the recursive method return a Stream of nodes instead of a List, then filter to keep only the leaves and finally collect to a list:

我会通过使递归方法返回节点流而不是List,然后过滤以仅保留叶子并最终收集到列表来实现:

public List<SpecTreeNode> getLeavesBelow() {
    return nodesBelow(this)
        .parallel()
        .filter(Node::isLeaf)
        .collect(Collectors.toList());
}

private Stream<SpecTreeNode> nodesBelow(SpecTreeNode node) {
    return Stream.concat(
               Stream.of(node), 
               node.chList.stream()
                      .flatMap(this::leavesBelow));
}

#1


1  

Just like this, right? Am I missing something?

就像这样,对吗?我错过了什么吗?

result.addAll(
    chList.parallelStream()
         .map(SpecTreeNode::getLeavesBelow)
         .flatMap(Collection::stream)
         .collect(Collectors.toList())
);

Unrelated to your question but because you're seeking performance improvements: you may see some gains by specifying an initial size for your ArrayList to avoid reallocating multiple times.

与您的问题无关,但是因为您正在寻求性能改进:您可以通过指定ArrayList的初始大小来避免多次重新分配,从而获得一些收益。

A LinkedList may be a preferable data structure if you can't anticipate the size, as all you're doing here is continually appending to the end of the list. However, if you need to randomly access elements of this list later then it might not be.

如果你无法预测大小,LinkedList可能是一个更好的数据结构,因为你在这里所做的只是不断追加到列表的末尾。但是,如果您需要稍后随机访问此列表的元素,则可能不会。

#2


1  

I would do it by making the recursive method return a Stream of nodes instead of a List, then filter to keep only the leaves and finally collect to a list:

我会通过使递归方法返回节点流而不是List,然后过滤以仅保留叶子并最终收集到列表来实现:

public List<SpecTreeNode> getLeavesBelow() {
    return nodesBelow(this)
        .parallel()
        .filter(Node::isLeaf)
        .collect(Collectors.toList());
}

private Stream<SpecTreeNode> nodesBelow(SpecTreeNode node) {
    return Stream.concat(
               Stream.of(node), 
               node.chList.stream()
                      .flatMap(this::leavesBelow));
}