I have a method that needs to loop through nested elements and return a string which should be concatenated as a result of the lopping through the tree. from searching, i believe recursion will be a easier method but I am unable to get the results desired.
Structure of data:
root
child 1
child 1.1
child 1.2
child 2
child 2.1
child 2.2
child 2.2.1
child 3
Okay that is the idea. I need to loop though starting from a child to find the path to the root by list the element from the child starting point to the root.
Eg: I am looking for child 2.2.1. The return answer should be:
child 2.2.1,child 2.2, child 2, root
Private String loopthrough(String name, String needed LinkedList myList)
List<String>Children = new ArrayList<String>();
for (String child : children)
{
if (child.isParentOf(needed ))
{ name+=child.getName
}
else{
goneThrough.add(child);
}
}
children = goneThrough;
for (String child : children)
{
loopthrough(child);
}
You could avoid recursion by pushing the nodes you visit on the desired path as you descend the tree, so that they will get popped off in the order you wish to display them in.
Use a StringBuilder (or PrintWriter, or StringWriter) as in-out parameter.
StringBuilder sb = new StringBuilder():
tree.dumpTree(sb);
System.out.println(sb);
String s = sb.toString();
This has the additional advantage that not a on every call a concatenation of Strings to new Strings happens.
In this case you can build a result on coming back from the recursion. I still do not understand what your data structure is, and what would be the correct parameters. With String:
private String loopthrough(String name, String needed, List<?> myList)
{
if (name.equals(needed)) {
return name;
}
for (String child : children) {
String partialResult = loopthrough(child, ...);
if (partialResult != null) {
return name + " " + partialResult;
}
}
return null; // Not found in this subtree.
}
Of course we cannot know the datastructure you are using. I assume here, that children are the immediate child nodes. And in the recursion one would rather parse the node, that the name String.
Related
I need to create a data structure in java which can represents hierarchy of data. Example use case is shown in the image below.
an organization hierarchy
In my case only the leaves level will have data, and the internal nodes should act like indexes. I should be able to get data from the data structure using multiple keys(Composite keys).
Is it okay to use nested maps, or should I implement an m way tree(B tree/B+ tree) for this use case.
If the structure of the nested data is constant you could use normal classes with properties.
If the structure is dynamic I would use Maps, the interface and ignore the implementation.
About using using a custom tree structure, if you can use classes, thats better. If you use Maps, I would start with a HashMap and if you find it to be a problem your can replace your Map to something else later.
Obviously you have to use Tree like data structure. Here is the sample code of that.
High level code idea
class Entity{
// declare you attributes and below two properties
List<Entity> children;
boolean isleafNode;// for parent node its 'false' and for leaf node it will 'true'
}
you can implement Trie for this use case. Iterate over composite key and return data if found.
class definition:
public class TrieNode {
private HashMap<String, TrieNode> children;
private Data data;
private boolean isLeaf;
// ...
}
find query will look like:
public Data find(List<String> compositeKey) {
TrieNode current = root;
for (String key: compositeKey) {
TrieNode node = current.getChildren().get(key);
if (node == null) {
return null;
}
current = node;
}
if(current.isLeaf()) {
return current.getData();
} else {
return null;
}
}
insert will look like:
public void insert(List<String> compositeKey, Data data) {
TrieNode current = root;
for (String key: compositeKey) {
current = current.getChildren()
.computeIfAbsent(key, c -> new TrieNode());
}
current.setLeaf(true);
current.setData(data);
}
I have two columns in a table called Folder and Parent. And in my service I have a method called FolderService.getAllParents(s) - where (s) is a string. However a folder can also be in the parent column and I m trying to do a recursive formula to get all the folders and their respective parents.
For example Documents (parent) and Film (folder) also Film (parent) and Reviews(folder) ,Reviews(parent) and name(folder) and so on. I want to get all the parents and folder according to the string searched. Here's the recursive formula that i m stuck on:
public ArrayList<String> getParents(String s){
ArrayList<String> mn = new ArrayList<String>();
for(FolderManager y:FolderService.getAllParents(s)){
if(y.getParent().isEmpty()){
mn.add(y.getFolder());
return mn;
}else{
return getParents(y.getFolder());
}
}
return mn;
}
I m not getting any errors but I m only getting till
Documents (parent) - Film (folder) Film (parent) - Reviews(folder)
First of all, if I understood you correctly, your FolderService.getAllParents() will always return one object (because one child can have only one parent, isn't it?).
Then I don't think recursion is needed here. It can be done with a simple loop:
List<String> getParents(FolderManager fm) {
List<String> parents = new ArrayList<>();
while (fm.getParent() != null) {
parents.add(fm.getParent().getFolder());
fm = fm.getParent();
}
return parents;
}
I want to move a tree from database in java.
First I get ResultSet from DB:
String selectTree = "select id, id_parent, text from tree ";
ResultSet resultSet = statement.executeQuery(selectTree);
resultSet.last();
sizeOfSelect = resultSet.getRow();
resultSet.beforeFirst();
list = new ArrayList<Node>(sizeOfSelect);
while(resultSet.next()) {
list.add(new Node(resultSet.getInt(1),
resultSet.getInt(2),
resultSet.getString(3)));
}
Now I have an array of nodes:
class Node<T> {
private int id;
private int parent_id;
private String text;
Node(int _id, int _parentId, String _text) {
this.id = _id;
this.parent_id = _parentId;
this.text = _text;
}
//getters & setters here
How can I obtain the same tree in java?
Could you tell me the line of thought, please.
I have made progress in solution.
I turning array of RawNode in map thus:
for(RawNode rawNode : tmpList) {
tmpMap.put(rawNode.getId(), dependsId(rawNode.getId()));
}
Where method dependsId() is:
private List<RawNode> dependsId(int id) {
List<RawNode> tmpDependList = new ArrayList<>();
for(RawNode rawNode : tmpList) {
if(rawNode.getParentId() == id) {
tmpDependList.add(rawNode);
}
}
return tmpList;
}
What should I do next? How transform this map in array of Node with parent and children?
Right now, your "raw" Nodes look like this:
class RawNode {
private int id;
private int parent_id;
private String text;
[ hint: I renamed that class declaration; and removed the <T> part which doesn't make any sense given the fact that you have nothing generic in that class; at least from what you showing ]
and ideally, that would mean that there is exactly ONE Node object for each ID. In other words; over time, you created objects like:
RawNode rootWithoutParent = new Node(0, -1, "root");
RawNode firstChildParent = new Node(1, 0, "root");
And you have all these objects in an array/list. Now you could transform those RawNodes, into "real" Nodes, and that one could look like:
class Node {
private int id;
private Node parent;
private List<Node> children = new ArrayList<>();
private String text;
Translation could be done in multiple iterations.
First, you create one Node per RawNode (and for later, we remember specific information in two maps):
List<Node> nodes = new ArrayList<>();
Map<Node, RawNode> rawNodesByNode = new HashMap<>();
Map<Integer, Node> nodesById = new HashMap<>();
for(RawNode rawNode : tmpList) {
Node node = new Node();
node.setId(rawNode.getId());
node.setText(rawNode.getText());
rawNodesByNode.put(node, rawNode);
nodesById.put(rawNode.getId(), node);
}
What is missing?
First, the "link" from childs to their parent.
for(Node node : nodes) {
RawNode raw = rawNodesByNode.get(node);
int parentId = raw.getParentId();
Node parent = nodesById.get(parentId);
node.setParent(parent);
}
Second ("optional") the "link" from parents to all childs:
for(Node node : nodes) {
Node parent = node.getParent(); // should be != null by now
parent.addChild(node);
}
with:
void addChild(Node node) {
children.add(node);
}
( please note: the children list is created directly when you do a Node.new() call; but at that point, it is empty. And beyond that: I didn't put my code into a compiler; it is meant as "pseudo code", to get you going; and give some insights into the required steps. There is also a certain potential for "bugs" - conditions where you need special checking to handle cases like the "root node" which doesn't have a parent; in other words: don't just copy&paste my code: understand what it is supposed to do and work from there).
Hope that gives you enough ideas to get you going. And please note: all of this is just "work"; there is no "rocket science" involved; so the essential part is that you now engage and understand what you are about to do. So resist the urge to ask yet-another question; instead: start working.
Well, if you want tree, your Node definitely lacks some links to other nodes(for parent at least), i'd suggest replacing parent_id in Node to Node parentNode, and set it according to parent_id from database, for example add them all to map at first, mapped by Map<Integer, Node> someMap, where integer is id, then when iterate trhough each and do:
list.add(new Node(resultSet.getInt(1),
someMap.get(resultSet.getInt(2)),
resultSet.getString(3)));
oh, and don't forget to check if that parent id is not null.
I don't really use result set often, but i suppose it would be better to move them from there to some temporary list.
Really sorry, don't have time to write everything as it should be, but i hope you've got my idea
specifically I need to represent the following:
The tree at any node can have an arbitrary number of children
Each parent node (after the root) is just a String (whose children are also Strings)
I need to be able to get parent and list out all the children (some sort of list or array of Strings) given an input string representing a given node
Dynamically populating the tree structure based on reference relationship between parent and child.
Example given is I have one member1 sponsor another member2, and member2 sponsor member 3 and so and so for. Already have the table records relationship
Is there an available structure for this ???
My data is from DB or a List, I will loop through the information with the name and the relation to determine if the node is a root, parent or a child.
So during the loop, I found a child, I need a reference to the parent so that I can compare the child relation to the parent before adding the child to its parent.
The closest code I found .
public class TreeNode<T> implements Iterable<TreeNode<T>> {
T data;
TreeNode<T> parent;
List<TreeNode<T>> children;
public TreeNode(T data) {
this.data = data;
this.children = new LinkedList<TreeNode<T>>();
}
public TreeNode<T> addChild(T child) {
TreeNode<T> childNode = new TreeNode<T>(child);
childNode.parent = this;
this.children.add(childNode);
return childNode;
}
// other features ...
}
Sample usage:
TreeNode<String> root = new TreeNode<String>("root");
{
TreeNode<String> node0 = root.addChild("node0");
TreeNode<String> node1 = root.addChild("node1");
TreeNode<String> node2 = root.addChild("node2");
{
TreeNode<String> node20 = node2.addChild(null);
TreeNode<String> node21 = node2.addChild("node21");
{
TreeNode<String> node210 = node20.addChild("node210");
}
}
}
This is what I have done so far. The parent will get overwritten by the latest entry so hence I am unable to retrieve what I have added previously .
public static TreeNode<String> getSet1() throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = reader.readLine()) != null) {
String[] items = line.split(":");
String name = items[0];
String parent = items[1];
String type = items[2];
if (parent.equalsIgnoreCase("-") && type.equalsIgnoreCase("mainparent")) {
root = new TreeNode<String>(name);
} else if (type.equalsIgnoreCase("ChildParent") && parent.equalsIgnoreCase(root.toString())) {
childParent = root.addChild(name);
} else if (type.equalsIgnoreCase("Child") && parent.equalsIgnoreCase(childParent.toString())) {
child = childParent.addChild(name);
}
}
return root;
}
Your diagram indicates a tree of arbitrary depth, but your code only handles grandparent -> parent -> child relationships (with a single grandparent at the root).
I would ignore the type, as all you need is the name of a person and the name of their parent. If the parent name is a dash, you know you have the root.
Now for each person, you need to get the parent node already in the tree (assuming parents come before children in the list - if that's not the case, the problem becomes significantly more complex, as you would have to store orphaned persons temporarily and for each new person see if they are the parent of an orphaned person).
In order to get the parent by name, you should store each person you have already processed in a second data structure, parallel to the tree. The second data structure should make it easy to look someone up by name. Maps, and in particular Hashtables, are ideal for this. This is how it works:
Map processedPersonsMap=new Hashtable<String, TreeNode<String>>();
For each person, you store them in the map, indexed by their name:
TreeNode<String> person=...;
processedPersonsMap.put(person.getData(), person);
When you read in a new person and their parent's name is not a dash, you look up the parent:
String parentName=items[1];
TreeNode<String> parent=processedPersonsMap.get(parentName);
In this way, no matter how deep the tree is, you will always find the right parents. However, keep in mind that this requires a valid input file where each child comes after their parent, and which does not contain circular references or missing parents.
If those conditions are not met, you have to handle them explicitly.
Say I have a csv file where one of the columns is unix timestamp. It is not sorted on that, but following those in order could be a useful relationship. When I want that, I could use ORDER BY, but adding relationship pointers should be faster right, and make use of the NOSQL? Do I have to sort this and add the relationship as I ingest, or can I do it after a query?
After I run the first query and get a subset back:
result = engine.execute(START...WHERE...ORDER BY time)
Can I then go through results adding this relationship like:
prev.createRelationshipTo(next, PRECEDES);
I tried two different ways using foreach or iterator and both had runtime errors casting a string to a Node:
for (Map<String, Object>row : result) {
String n = (String) row.values().iterator().next();
System.out.println(n);
}
Iterator<Node> nodes = result.columnAs("n.chosen");
if (nodes.hasNext()) {
Node prev = nodes.next();
while (nodes.hasNext()) {
Node n = nodes.next();
prev.createRelationshipTo(n, null);
prev = n;
}
}
Also, there is the edge case of two rows having the same timestamp. I don't care about the order that is chosen, but I want it to not break the relation chain.