我想在Java8节点流中转换树
这是存储可以选择的数据的节点树
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();
}
}
我想获得所选数据的集合
我想做那样的事情:
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;
}
问题在于找到stream()
的实现,我想我可以帮助一些人分享我的解决方案,我会知道是否存在某些问题或更好的方法。
起初它是针对素数TreeNode
,但我将问题推广到各种树
答案 0 :(得分:9)
kwisatz答案的一小部分内容。
此实施:
this.getChildren().stream()
.map(SelectTree::stream)
.reduce(Stream.of(this), Stream::concat);
会更加渴望,我。即在流创建期间将遍历整个层次结构。如果你的hirarchy很大,让我们说,你正在寻找一个匹配某个谓词的节点,你可能想要一个更懒惰的行为:
Stream.concat(Stream.of(this),
this.getChildren().stream().flatMap(SelectTree::stream));
在这种情况下,在创建流时只会检索根节点的子节点,搜索节点不一定会导致遍历整个层次结构。
两种方法都将展示DFS迭代顺序。
答案 1 :(得分:7)
我发现stream()
的这个实现是DFS树遍历:
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));
}
}
}
如果你不能改变像primefaces TreeNode
(org.primefaces.model.TreeNode
)这样的树实现,你可以在另一个类中定义一个方法:
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)) ;
}
}
答案 2 :(得分:0)
使用任何节点类的更通用的方法是为该方法添加一个参数,该参数返回子代:
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)));
}
}
使用文件的示例:
TreeNodeStream.of(
new File("."), f -> f.isDirectory() ? Arrays.asList(f.listFiles()) :
Collections.emptySet())
.filter(f -> f.getName().endsWith(".java"))
.collect(Collectors::toList);