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<D> {
private D data;
private boolean selected = false;
private SelectTree<D> parent;
private final List<SelectTree<D>> children = new ArrayList<>();
public SelectTree(D data, SelectTree<D> parent) {
this.data = data;
if (parent != null) {
this.parent = parent;
this.parent.getChildren().add(this);
}
}
public D getData() {
return data;
}
public void setData(D data) {
this.data = data;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public SelectTree<D> getParent() {
return parent;
}
public void setParent(SelectTree<D> parent) {
this.parent = parent;
}
public List<SelectTree<D>> getChildren() {
return children;
}
public boolean isRoot() {
return this.getParent() == null;
}
public boolean isLeaf() {
return this.getChildren() == null || this.getChildren().isEmpty();
}
}
I want to get a collection of the selected data
I want to do something like that:
public static void main(String[] args) {
SelectTree<Integer> root = generateTree();
List<Integer> selectedData = root.stream()
.peek(node -> System.out.println(node.getData()+": "+node.isSelected()))
.filter(node-> node.isSelected())
.map(node-> node.getData())
.collect(Collectors.toList()) ;
System.out.println("\nselectedData="+selectedData);
}
private static SelectTree<Integer> generateTree() {
SelectTree<Integer> n1 = new SelectTree(1, null);
SelectTree<Integer> n11 = new SelectTree(11, n1);
SelectTree<Integer> n12 = new SelectTree(12, n1);
n12.setSelected(true);
SelectTree<Integer> n111 = new SelectTree(111, n11);
n111.setSelected(true);
SelectTree<Integer> n112 = new SelectTree(112, n11);
SelectTree<Integer> n121 = new SelectTree(121, n12);
SelectTree<Integer> n122 = new SelectTree(122, n12);
return n1;
}
The problem was to find the implementation of stream()
and I think I could help some people sharing my solution and I would be interested in knowing if there are some issues or better ways of doing this.
At first it was for primefaces TreeNode
but I generalize the problem to all kinds of trees.
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.