Getting all nodes in a BeanTreeView - java

I have a BeanTreeView that shows a some nodes. And I have another component that isn't netbeans-related that needs to know what is in the tree at this moment. Preferably just a straight list of the nodes in the tree. (Clarification; when I talk about nodes here I mean netbeans nodes, not the TreeNodes in a JTree.)
I haven't found any useful methods of doing this. I can't seem to get the information from the associated ExplorerManager that's connected to the BeanTreeView. So far I've subclassed the BeanTreeView and added the private method
private List<Object> getNodesAsList(){
LinkedList<Object> result = new LinkedList<>();
for (int i = 0; i < tree.getRowCount(); i++) {
TreePath pathForRow = tree.getPathForRow(i);
Object lastPathComponent = pathForRow.getLastPathComponent();
result.add(lastPathComponent);
}
return result;
}
The Object I get from getLastPathComponent is a VisualizerNode, which holds the node I want to get. But I can't cast to VisualizerNode since it's not public in org.openide.explorer.view. And it's final. And there's no getters for the node anyway...
Any ideas? I feel like there's something I've missed with the ExplorerManager...
Update; this worked for me, could probably be done more elegant. Thanks paddy!
private List<Node> getNodesInTree(){
LinkedList<Node> result = new LinkedList<>();
ExplorerManager em = ExplorerManager.find(this);
for (Node node : em.getRootContext().getChildren().getNodes()) {
result.add(node);
result.addAll(getChildNodesInTree(node));
}
return result;
}
private List<Node> getChildNodesInTree(Node root){
LinkedList<Node> result = new LinkedList<>();
if(root.getChildren().getNodesCount() > 0){
if(isExpanded(root)){
for (Node node : root.getChildren().getNodes()) {
result.add(node);
result.addAll(getChildNodesInTree(node));
}
}
}
return result;
}

You could use ExplorerManager.getRootContext(). This returns the root Node shown in your ExplorerManager. From this node you could iterate through all the other nodes (using Node.getChildren()) and create your own list. I am not aware of a function that handles that for you.

Related

Stream Spliterator error after concat Java

When attempting to create an iterator from a Stream that was concatenated from two previous streams, I get a NoSuchElementException, as the iterator doesn't recognise that the Stream has elements due to some problems with the Spliterator. The concatenated Stream seems to have two spliterators, despite the previous streams being of the same type. I also get this error when I tried to convert the concatenated stream into an array to try get round the problem.
Stream<Node> nodeStream = Stream.of(firstNode);
while (!goal) {
Iterator<Node> iterator = nodeStream.iterator();
Node head = iterator.next();
Stream<Node> tail = Stream.generate(iterator::next).filter(n -> n != head);
Node[] newNodes = head.expand(end);
if (newNodes.length == 1) {
goal = true;
endNode = newNodes[0];
}
nodeStream = Stream.concat(Arrays.stream(newNodes), tail);
nodeStream = nodeStream.sorted(Comparator.comparing(n -> n.routeCost(end)));
}
The error is as follows:
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Spliterators$1Adapter.next(Spliterators.java:688)
at java.base/java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1358)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:292)
at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:298)
at java.base/java.util.stream.Streams$ConcatSpliterator.tryAdvance(Streams.java:723)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:292)
at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
at java.base/java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:298)
at java.base/java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
at java.base/java.util.Spliterators$1Adapter.next(Spliterators.java:687)
at inf.ed.ac.uk.Route.generateRoute(Route.java:35)
I am trying to expand the first node (returns 16 new nodes) add them to the stream, sort it, and repeat, this is part of an implementation of the A* algorithm on gps coordinates
Code for Node is
public class Node {
boolean goal = false;
Node parent;
final LngLat coords;
LngLat.Compass direction;
double cost;
private Route route;
public Node[] expand(LngLat end) {
ArrayList<Node> nodes = new ArrayList<>();
for (LngLat.Compass direction: LngLat.Compass.values()) {
Node node = new Node(coords.nextPosition(direction), this, direction);
if (noFlyClear(node)) {
if (!route.contains(node)) {
if (node.coords.closeTo(end)) {
node.goal = true;
return new Node[]{node};
}
nodes.add(node);
route.visited.add(node);
}
}
}
return nodes.toArray(Node[]::new);
}
But that's since I changed to ArrayLists
I'm still unsure what the issue was originally

How to iterate through a list of nodes which might have sub-lists of nodes (unknown depth levels)

I have a list of nodes, and each node might have a list of subNodes (the number of levels are unknown):
class Node {
int score;
boolean selected;
List<Node> subNodes;
}
Here's how an hypothetical structure might look like:
NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
Combinations are just countless. I need a way to sum NODE.score for all those nodes that have NODE.selected set to true, possibly using Java 8 features. Any hints would be really appreciated.
Something like:
public int recursiveTotal(final Node node) {
//node not select, don't count the node or any of its subnodes
if (!node.selected) {
return 0;
}
//no subnodes, only node score counts
if (node.subNodes.isEmpty()) {
return node.score;
}
//node has subnodes, recursively count subnode score + parent node score
int totalScore = node.score;
for (final Node subNode : node.subNodes) {
totalScore += recursiveTotal(subNode);
}
return totalScore;
}
Coded using stackoverflow as an IDE, no guarantee against compilation errors ;)
Create a recursive method in your Node class which returns a stream of nodes concatenating a stream of the parent node and the sub nodes:
class Node {
int score;
boolean selected;
List<Node> subNodes;
public Stream<Node> streamNodes() {
return Stream.concat(Stream.of(this), subNodes.stream().flatMap(Node::streamNodes));
}
}
and use it like below to stream over your list:
List<Node> myNodes = //your list
int sum = myNodes.stream()
.flatMap(Node::streamNodes)
.filter(Node::isSelected)
.mapToInt(Node::getScore)
.sum();
TL;DR
Judging by the structure, you've provided each Node in your List is the root of an N-ary Tree data structure (I assume that there are no circles).
And in order to get the required data, we can utilize one of the classic tree-traversal algorithms. In case when the average depth is lower than the average width Depth first search algorithm would be more suitable because it would be more space-efficient, in the opposite situation it would be better to use Breadth first search. I'll go with DFS.
It's easier to come up with a recursive implementation, so I'll start with it. But it has no practical value in Java, hence we would proceed with a couple of improvements.
Streams + recursion
You can create a helper-method responsible for flattening the nodes which would be called from the stream.
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.flatMap(node -> flatten(node).stream())
.filter(Node::isSelected)
.mapToLong(Node::getScore)
.sum();
Recursive auxiliary method:
public static List<Node> flatten(Node node) {
if (node.getSubNodes().isEmpty()) {
return List.of(node);
}
List<Node> result = new ArrayList<>();
result.add(node);
node.getSubNodes().forEach(n -> result.addAll(flatten(n)));
return result;
}
No recursion
To avoid StackOverflowError method flatten() can be implemented without recursion by polling and allocating new nodes on the stack (represented by an ArrayDeque) iterativelly.
public static List<Node> flatten(Node node) {
List<Node> result = new ArrayList<>();
Deque<Node> stack = new ArrayDeque<>();
stack.add(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
result.add(current);
current.getSubNodes().forEach(stack::push);
}
return result;
}
No recursion & No intermediate data allocation
Allocating intermediate data in the form of nodes which eventually would not be used is impractical.
Instead, we can make the auxiliary method to be responsible for calculating the total score produced by summarizing the score of each selected node in the tree of nodes.
For that we need to perform isSelected() while traversing the tree.
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.mapToLong(node -> getScore(node))
.sum();
public static long getScore(Node node) {
long total = 0;
Deque<Node> stack = new ArrayDeque<>();
stack.push(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
if (current.isSelected()) total += current.getScore();
current.getSubNodes().forEach(stack::push);
}
return total;
}

Data structures get maximum value at each level of N-ary tree

Lets say I have a n-ary tree something like below I need to find maximum value at each level and return like :
[8,7,32] .
8
4 3 7
1 4 3 3 5 6 7 12 32 3 1
My Node will look something like below :
public class Node {
public int val;
public List<Node> children;
public Node() {
}
public Node(int _val,List<Node> _children) {
val=_val;
children=_children;
}
I tried through recursion at each level get the elements and find the maximum but unable to do so.
We can get the level-maximum by a level order traversal / Breadth-first search. The idea is that we have a list/queue of nodes on one level. For all nodes in this list the algorithm does two things:
It calculates the maximum value on this level.
It iterates over all nodes of the list/queue, gets all children of those nodes and put them in a new list/queue, which it can then process in the next iteration.
The algorithm starts with a list/queue holding the root of the (sub)-tree and ends when the list/queue is empty.
This can be expressed nicely with Stream operations:
public static List<Integer> getMaxValuePerLevel(Node node) {
final ArrayList<Integer> maxPerLevel = new ArrayList();
maxPerLevel.add(node.getValue());
List<Node> children = node.getChildren();
while (!children.isEmpty()) {
maxPerLevel.add(children.stream()
.mapToInt(Node::getValue)
.max()
.getAsInt());
children = children.stream()
.map(Node::getChildren)
.flatMap(List::stream)
.collect(Collectors.toList());
}
return maxPerLevel;
}
Ideone demo
This implementation has two nice properties:
It is iterative, not recursive, i.e. the algorithm is not subject to a StackOverflowError
It has linear time- and memory complexity
With a little bit of effort, we are even able to make the algorithm work with generic Node<T extends Comparable<T>>:
public static <T extends Comparable<T>> List<T> getMaxValuePerLevel(Node<T> node) {
final ArrayList<T> maxPerLevel = new ArrayList<>();
maxPerLevel.add(node.getValue());
List<Node<T>> children = node.getChildren();
while (!children.isEmpty()) {
final Node<T> defaultNode = children.get(0);
maxPerLevel.add(children.stream()
.map(Node::getValue)
.max(Comparator.naturalOrder())
.orElseGet(defaultNode::getValue));
children = children.stream()
.map(Node::getChildren)
.flatMap(List::stream)
.collect(Collectors.toList());
}
return maxPerLevel;
}
Ideone demo
The root node is going to be the highest of its level. For the subsequent levels, call Collections.sort() (or any other comparison that will order your list) on the list of children nodes and take the last element (or whichever has the highest value according to the sorting method you used). Then iterate through the list of children nodes that you just sorted and for each node, apply the same treatment to its list of children.
A recursive solution is surprisingly simple. First create a list to hold the result. Then iterate through all the nodes: at each node you compare the node's value with the value in the list at the same level. If the node's value is greater, you replace the value in the list.
class Node {
public int val;
public List<Node> children;
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
public List<Integer> getMaxPerLevel() {
List<Integer> levels = new ArrayList<>();
getMaxPerLevel(0, levels);
return levels;
}
private void getMaxPerLevel(int level, List<Integer> levels) {
if (level >= levels.size()) {
levels.add(level, val);
} else {
levels.set(level, Math.max(val, levels.get(level)));
}
for (Node child : children) {
child.getMaxPerLevel(level + 1, levels);
}
}
}
Thanks everyone I did using below solution:
public List<Integer> levelOrder(Node node){
List<Integer> result = new ArrayList<>();
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
while(!queue.isEmpty()) {
int size = queue.size();
List<Integer> currentLevel = new ArrayList<Integer>();
for(int i=0;i<size;i++) {
Node current = queue.remove();
currentLevel.add(current.val);
for(Integer inte:currentLevel) {
System.out.println(inte);
}
if(current.children !=null) {
for(Node node1:current.children)
queue.add(node1);
}
}
result.add(Collections.max(currentLevel));
}
return result;
}

Java get all permutations of 5 objects

I am struggling to implement an algorithm that seems rather easy...
So I have 5 or less Objects, each with say different name. I need to find all permutations of these 5 or less objects. I tried to use tree-like structure where each element has 1 parent and n<=5 children. I am using ArrayList to store the child elements. I think what I need is recursion but I am not sure how it should be done.
Here's some of my code
public class Tree {
private ArrayList<Tree> children = new ArrayList<>();
private Tree parent = null;
private String data;
public Tree(String data) {
this.data = data;
}
public ArrayList<Tree> addChild(ArrayList<Tree> childrenPased) {
ArrayList<Tree> childrenToUse = (ArrayList<Tree>) childrenPased.clone();
childrenToUse.remove(this);
ArrayList allParents = this.getAllParents();
childrenToUse.removeAll(allParents);
childrenToUse.removeAll(children);
if(childrenToUse.size() > 0) {
for(Tree child : childrenToUse) {
children.add(child);
child.parent = this;
}
}
return children;
}
public ArrayList<Tree> getAllParents(){
ArrayList<Tree> allParents = new ArrayList<>();
Tree tempParrent = this.parent;
if(tempParrent != null){
allParents.add(tempParrent);
tempParrent = this.parent.getParent();
while(tempParrent != null){
allParents.add(tempParrent);
tempParrent = tempParrent.parent;
}
}
return allParents;
}
To use this I just made 5 (essentially 4) nested for loops to add children via the above method to the value returned in the outer for loop.
The results I am looking for is 120 (5*4*3*2*1) permutations of these 5 elements. Of course stored somehow so I can retrieve them and compare them after.
There should be some logic in my logic and how I deal with the problem, I would love if someone could put me in the right direction, I guess possibly using recursion...?

Swap collections during iteration

I have a List of Nodes which contains nested list of child nodes. I am trying to iterate through all of them to find a particular node.Currently I start at the child nodes from the root level, then go one level deep to sub child node and so on using for-each loop.
This is my code:
List<Node> children = root.getChildren();
boolean found = false;
while (!found) {
for (Node node : children) {
if (!node.getData().toString().toUpperCase().contains("BRANCH")) {
if(condition){//some processing}
} else {
//swap children with sub children
if (children.get(0) != null) {
children = children.get(0).getChildren(); // this operation is not possible during iteration
}
}
} else {
continue;
}
}
}
}
If child node doesn't find any match, then I need to swap the collection with sub child node and continue iteration and so on.
Is there a better way to iterate through a nested nodelist of children?
Instead of swapping the collections, you could add the elements to a queue, and keep iterating till the queue is empty (i.e. you didn't find a match). Or you do find a match and return early.
public static void algorithm(Node root) {
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()) {
Node current = q.poll();
if(current .getData().toString().toUpperCase().contains("BRANCH")) {
continue;
}
if(condition){
//some processing
return;
} else {
q.addAll(current.getChildren());
}
}
}
algorithm(root);
You can't swap like this mid-iteration. Remember that your for loop is translated in Java like this:
for (Iterator<Node> it = children.iterator(); it.hasNext(); ) {
Node node = it.next();
// The rest of it
}
So even if you change what children is, your iterator stays as it is.
I would suggest using a Queue to help you here.
PS Do you really want to skip all of the non-first children? That appears to be what you're currently doing.

Categories

Resources