How to convert a tree structure to a Stream of nodes in java

后端 未结 3 1068
甜味超标
甜味超标 2020-12-16 02:42

I want to convert a tree in a Java8 stream of nodes.

Here is a tree of nodes storing data which can be selected:

public class SelectTree {

           


        
相关标签:
3条回答
  • 2020-12-16 03:18

    A more general approach using any node class is to add a parameter for the method, which returns the children:

    public class TreeNodeStream {
      public static <T> Stream<T> of(T node, Function<T, Collection<? extends T>> childrenFunction) {
        return Stream.concat( //
          Stream.of(node), //
          childrenFunction.apply(node).stream().flatMap(n -> of(n, childrenFunction)));
      }
    }
    

    An example using File:

    TreeNodeStream.of(
      new File("."), f -> f.isDirectory() ? Arrays.asList(f.listFiles()) :
                                            Collections.emptySet())
      .filter(f -> f.getName().endsWith(".java"))
      .collect(Collectors::toList);
    
    0 讨论(0)
  • 2020-12-16 03:21

    One small addition to kwisatz's answer.

    This implementation:

    this.getChildren().stream()
            .map(SelectTree::stream)
            .reduce(Stream.of(this), Stream::concat);
    

    will be more eager, i. e. the whole hierarchy will be traversed during a stream creation. If your hirarchy is large and, let's say, you're looking for a single node matching some predicate, you may want a more lazy behaviour:

    Stream.concat(Stream.of(this),
                  this.getChildren().stream().flatMap(SelectTree::stream));
    

    In this case, only the children of the root node will be retrieved during a stream creation, and a search for a node won't necessarily result in the whole hierarchy being traversed.

    Both approaches will exhibit the DFS iteration order.

    0 讨论(0)
  • 2020-12-16 03:24

    I find this implementation of stream() which is a DFS tree traversal:

    public class SelectTree<D> {
    
      //...
    
      public Stream<SelectTree<D>> stream() {
        if (this.isLeaf()) {
          return Stream.of(this);
        } else {
          return this.getChildren().stream()
                    .map(child -> child.stream())
                    .reduce(Stream.of(this), (s1, s2) -> Stream.concat(s1, s2));
        }
      }
    }
    

    If you can't change the tree implementation like for primefaces TreeNode (org.primefaces.model.TreeNode) you can define a method in an other class:

      public Stream<TreeNode> stream(TreeNode parentNode) {
        if(parentNode.isLeaf()) {
          return Stream.of(parentNode);
        } else {
          return parentNode.getChildren().stream()
                    .map(childNode -> stream(childNode))
                    .reduce(Stream.of(parentNode), (s1, s2) -> Stream.concat(s1, s2)) ;
        }
      }
    
    0 讨论(0)
提交回复
热议问题