I basically want to get the deepest child of a parent recursively.
Function that i am using to get all the children of a parent
void addChildren(Children parent, List<Children> children) {
if(parent.getChildren() == null) {
return;
}
if(null != parent.getChildren()) {
for(Children child : parent.getChildren()) {
children.add(child);
addChildren(child, children);
}
}
}
Function call
List<Attributes> attribute = rootResp.getAttributes();
Attributes parentAtt = attribute.get(0);
Children parent = parentAtt.getChildren().get(0);
List<Children> children = new ArrayList<>();
addChildren(parent, children);
I am able to get all the children of a parent using these code but want to get the deepest child recursively.
Related
I have a Treeview TreeView<MyType> which I'd like to fill recursively from a MyType root object. The structure of the class MyType is the following:
public class MyType {
private Set<MyType> children = new HashSet<>();
public Set<MyType> getChildren() {
return children;
}
public void setChildren(Set<MyType> children) {
this.children = children;
}
}
So as you can see, the MyType root/parent has children of the same type, and those children can also have children from the same type. In practice, the depth between the root and its furthermost inheritant is no greater than 1000 level.
I want to fill the Treeview TreeView<MyType> recursively with tree items TreeItem<MyType>in the same tree structure as the data is stored in the MyType root file.
This is what I've tried so far but it's not working:
void buildTree(MyType parent, TreeItem<MyType> result) {
for (MyType child : parent.getChildren()) {
if (child.getChildren() == null || child.getChildren().isEmpty()) {
result.getChildren().add(new TreeItem<MyType>(child));
}
else {
TreeItem<MyType> tmp = new TreeItem<>(child);
buildTree(child, tmp);
}
}
}
Is it possible to make the filling work with the data structure provided?
It's more convenient to
A. Return TreeItems instead of passing both MyType and TreeItem to the recursive method calls.
B. Treat leafs as terminal cases instead of handling terminal cases at parents of leafs
This allows you to write the following code:
private TreeItem<MyType> buildSubtree(MyType root) {
TreeItem<MyType> result = new TreeItem<>(root);
if (root.getChildren() != null) {
for (MyType child : root.getChildren()) {
result.getChildren().add(buildSubtree(child));
}
}
return result;
}
Ok, I just figured it out. This is working as expected.
void buildTree(MyType parent, TreeItem<MyType> result) {
for (MyType child : parent.getChildren()) {
if (child.getChildren() == null || child.getChildren().isEmpty()) {
result.getChildren().add(new TreeItem<MyType>(child));
}
else {
TreeItem<MyType> tmp = new TreeItem<>(child);
buildTree(child, tmp);
result.getChildren().add(tmp);
}
}
}
I'm making a Tree and have been able to implement setting the Parent and child properly. I'm stuck at attempting to make a new layer of the tree, a grandchild in this case. It isn't a binary tree. Ideally I'd like to place the implementation of the new layer in either the constructor or in the addChild method. The following is what I have for my set up and the methods setting up my Parent and Children in my Tree
import java.util.ArrayList;
import java.util.List;
public abstract class TreeNode {
static int count; // store # tree nodes created. Generate IDs
private String id;// unique id # of nodes.
private List<TreeNode> children; // store all children of node
private TreeNode parent; // reference parent of the node. Null is node is root
public TreeNode(List<TreeNode> children) {
this.children = children;
this.count++;
this.id = Integer.toString(this.count);
int ctr = 0;
if (children != null) {
while (ctr < children.size()) {
children.get(ctr).setParent(this);
ctr++;
}
}
}
public void addChild(TreeNode child) { // add single child to current node
if (this.getChildren() == null) {
child.setParent(this);
this.setChildren(new ArrayList<TreeNode>());
this.children.add(child);
}
else {
child.setParent(this);
this.children.add(child);
}
}
Why is the class abstract? (I can't see an intent or a reason to extend it.)
Perhaps I don't understand what you're asking; from where I'm sitting, you already have support for "a new layer of the tree" -- as many as you want, in fact (at least of the class weren't abstract)...
TreeNode grandparent = new TreeNode(new ArrayList<TreeNode>()); // I recommend a zero-arg constructor that does this
TreeNode child = new TreeNode(new ArrayList<TreeNode>());
grandparent.addChild(child);
TreeNode grandchild = new TreeNode(new ArrayList<TreeNode>());
child.addChild(grandchild);
You now have a 3-level tree.
More Suggestions
Your id field
What is the purpose of the id filed? As you have it, you could get duplicates in a multi-threaded context. Better would be...
this.id = UUID.randomUUID().toString();
Every TreeNode would receive a unique id for certain (though they wouldn't be numeric or sequential).
Also, id values based on UUID will be unique even if you restart your VM and you're using persistent TreeNode objects.
The loop in your constructor
Better than...
while (ctr < children.size()) {
children.get(ctr).setParent(this);
ctr++;
}
would be...
for (TreeNode child : children) {
child.setParent(this);
}
I have an entity that has an attribute "father" is a reference to his father. (Like this in the database)
Now I need to create a tree in view, and I have to carry the children recursively.
I have made the method below, but I doubled the children. And not further if the (optimal) correct way to do this process.
Can somebody help me.
Thank you.
#Transactional(readOnly = true)
public Page<CategoriaDTO> findAll(Pageable pageable) {
log.debug("Request to get all Categorias");
Page<Categoria> result = categoriaRepository.findByPadreIsNull(pageable);
List<CategoriaDTO> categoriaDtos = new ArrayList<>();
for (Categoria categoriaAux : result) {
CategoriaDTO categoriaDto = categoriaMapper.categoriaToCategoriaDTO(categoriaAux);
categoriaDto.setHijos(categoriaMapper.categoriasToCategoriaDTOs(categoriaRepository.findByPadre(categoriaAux)));
hijos(categoriaDto.getHijos(),categoriaDto.getId());
categoriaDtos.add(categoriaDto);
}
return new PageImpl<CategoriaDTO>(categoriaDtos);
}
private void hijos(List<CategoriaDTO> hijos,Long padreId){
Categoria categoriaPadre = categoriaRepository.findOne(padreId);
if(! CollectionUtils.isEmpty(hijos)){
for (CategoriaDTO hijo : hijos) {
hijo.setHijos(categoriaMapper.categoriasToCategoriaDTOs(categoriaRepository.findByPadre(categoriaPadre)));
hijos(hijo.getHijos(),hijo.getId());
}
}
}
As I understand, in your entity you have a reference to the same entity.
So you could start the leaf and go up in the tree. Call the function recursively until the Entity has null parent(that means you reached the root). You also add the Entities to a list.
LinkedList<Category> list = new LinkedList<>();
public void getChildren(Category category) {
list.add(category);
if(category.getParent() == null)
return;
getChildren(category.getParent());
}
This is just an example, post your Entity for more details
In C# I found a method that was pretty sweet that allowed you to get all the descendants and all of THEIR descendants from a specified control.
I'm looking for a similar method for JavaFX.
I saw that the Parent class is what I want to work with since it is the class from which all Node classes that bear children are derived.
This is what I have so far (and I haven't really found anything on google with searches like "JavaFX get all nodes from a scene"):
public static ArrayList<Node> GetAllNodes(Parent root){
ArrayList<Node> Descendents = new ArrayList<>();
root.getChildrenUnmodifiable().stream().forEach(N -> {
if (!Descendents.contains(N)) Descendents.add(N);
if (N.getClass() == Parent.class) Descendents.addAll(
GetAllNodes((Parent)N)
);
});
}
So how do I tell if N is a parent (or extended from a parent)? Am I doing that right? It doesn't seem to be working... It's grabbing all the nodes from the root (parent) node but not from the nodes with children in them. I feel like this is something that's probably got an answer to it but I'm just asking the question... wrong. How do I go about doing this?
public static ArrayList<Node> getAllNodes(Parent root) {
ArrayList<Node> nodes = new ArrayList<Node>();
addAllDescendents(root, nodes);
return nodes;
}
private static void addAllDescendents(Parent parent, ArrayList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
nodes.add(node);
if (node instanceof Parent)
addAllDescendents((Parent)node, nodes);
}
}
I use this,
public class NodeUtils {
public static <T extends Pane> List<Node> paneNodes(T parent) {
return paneNodes(parent, new ArrayList<Node>());
}
private static <T extends Pane> List<Node> paneNodes(T parent, List<Node> nodes) {
for (Node node : parent.getChildren()) {
if (node instanceof Pane) {
paneNodes((Pane) node, nodes);
} else {
nodes.add(node);
}
}
return nodes;
}
}
Usage,
List<Node> nodes = NodeUtils.paneNodes(aVBoxOrAnotherContainer);
This source code uses the references of the existing nodes. It does not clone them.
This seems to get ALL nodes.
(In Kotlin)
fun getAllNodes(root: Parent): ArrayList<Node> {
var nodes = ArrayList<Node>()
fun recurseNodes(node: Node) {
nodes.add(node)
if(node is Parent)
for(child in node.childrenUnmodifiable) {
recurseNodes(child)
}
}
recurseNodes(root)
return nodes
}
I'd like to add to Hans' answer, that you have to check if parent is a SplitPane. Because SplitPanes have an empty list using getUnmodifiableChildren(), you'll have to use getItems() instead. (I do not know if there are other parents that do not provide their children via getUnmodifiableChildren(). SplitPane was the first I found...)
Unfortunately this won't get subnodes for most container components. If you try a TabPane as parent, you'll find no children, but you can find tabs in it with getTabs(). The same is with SplitPane and other. So every container will require a specific approach.
You could use node.lookupAll("*"), but it also doesn't look inside.
The solution could be a "Prototype" pattern - creating a meta class with common interface of getChildren() method, which is realized in subclasses - one for each type.
Approach example is given here.
This works for me:
public class FXUtil {
public static final List<Node> getAllChildren(final Parent parent) {
final List<Node> result = new LinkedList<>();
if (parent != null) {
final List<Node> childrenLvl1 = parent.getChildrenUnmodifiable();
result.addAll(childrenLvl1);
final List<Node> childrenLvl2 =
childrenLvl1.stream()
.filter(c -> c instanceof Parent)
.map(c -> (Parent) c)
.map(FXUtil::getAllChildren)
.flatMap(List::stream)
.collect(Collectors.toList());
result.addAll(childrenLvl2);
}
return result;
}
}
I wrote this n-array tree class. I want to write a method to add a child to a specific node in my tree.
First I should search my tree to find the father then add the child to that node children.
I don't know how I should declare my method
public class FamilyNode {
public String name;
public String Family;
public String sex;
public FamilyNode Father;
public FamilyNode Mother;
public FamilyNode Spouse=null;
public String status="alive";
public int population;
public ArrayList<FamilyNode> children=new ArrayList<FamilyNode>() ;
public FamilyNode(String firstname,String lastname,String sex1){
this.name=firstname;
this.Family=lastname;
this.sex=sex1;
this.population=this.children.size()+1;
}
public void SetParents(FamilyNode father,FamilyNode mother){
this.Father=father;
this.Mother=mother;
}
public void SetHW(FamilyNode HW){
this.Spouse=HW;
}
public int Number (){
int number_of_descendants = this.population;
if(this.Spouse!=null) number_of_descendants++;
for(int index = 0; index < this.children.size(); index++)
number_of_descendants = number_of_descendants+ this.children.get(index).Number();
return number_of_descendants;
}
public void AddChild(FamilyNode Father,FamilyNode child){
//the code here
}
}
I answered one of your related questions yesterday so let's continue with the code I posted :)
public class FamilyNode {
// ...
// ...
public FamilyNode findNodeByName(String nodeName){
if(name.equals(nodeName)){
// We found a node named nodeName, return it
return this;
}
// That's not me that you are looking for, let's see my kids
for(FamilyNode child : children){
if(child.findNodeByName(nodeName) != null)
// We found what we are looking, just return from here
return child;
}
// Finished looping over all nodes and did not find any, return null
return null;
}
public void addChild(FamilyNode child){
children.add(child);
}
}
Basically, you need to find the node you are looking for (by name in this case) and that can be done by the findNodeByName above. Once the node is found, add one child to it.
Use this code like this:
FamilyNode root = ...;
FamilyNode node = root.findNodeByName("Parent");
if(node != null) node.addChild(...);
NOTE
If you want to debug and visit all your tree nodes, use this method:
public FamilyNode findNodeByName(String nodeName){
System.out.println("Visiting node "+ name);
// That's not me that you are looking for, let's see my kids
for(FamilyNode child : children){
child.findNodeByName(nodeName)
}
// Finished looping over all nodes and did not find any, return null
return null;
}
This isn't exactly a tree, as children have potentially two parents rather than just one. It's a directed graph.
It would be good to change your variable and method names to be consistent with the usual Java convention of starting with a lowercase character.
In the interest of data consistency, you might consider making the addChild method something that simply adds to the list of children for the current node, but in your setParents method, update the child lists of both parents, adding the current node as a child there, by calling father.addChild(this) and mother.addChild(this) (protecting against them being null of course).
If the parents can be changed when they're previously set (presumably in error), you'll also need to remove the current node from previously set parents. For this, you might need a removeChild(FamilyNode child) method. Again for data consistency, this method should probably also set the appropriate parent field in the child node to null.