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;
}
Related
I have a method that allows removing the publication by a specific year.
However, I want to put all the publication which I will be removed into a new array and print them.
Any suggestion or help?
Thank you.
enter code here
public void removeYear(int removeYear)
{
Iterator<Publication> pb = publicationList.iterator();
while(pb.hasNext()){
Publication publication = pb.next();
if(publication.getYear() == removeYear){
pb.remove();
}
}
}
First what you should do is change the return type of the method to List because besides the deleting part we also want to save data to a new List so when calling this method it will return a List with the deleted data.
public List<Publication> removeYear(int removeYear){
And you have to declare a new List of Publication inside the method, so there we can save the deleted Publications
List<Publication> listNew = new ArrayList<>();
And we simply save the object with the add() method
listNew.add(publication);
All the code
public List<Publication> removeYear(int removeYear){
Iterator<Publication> pb = publicationList.iterator();
List<Publication> listNew = new ArrayList<>();
while(pb.hasNext()){
Publication publication = pb.next();
if(publication.getYear() == removeYear){
listNew.add(publication);
pb.remove();
}
}
return listNew;
}
Here we have returned a new list with deleted Publications.
And later if you want to print it simply call the method
List<Publication> deletedList = classIntance.removeYear(2000);
And print it
System.out.println("Deleted Publication are");
deletedList.stream().forEach(System.out::println);
The following approach may not be optional but seems to be a bit cleaner:
filter out the publications to be deleted by year
Use List::removeAll to complete removal:
public void removeYear(int removeYear) {
List<Publication> toDelete = publicationList.stream()
.filter(p -> p.getYear() == removeYear)
.collect(Collectors.toList());
// use publications from `toDelete` as needed
// ...
publicationList.removeAll(toDelete);
}
Another approach may be based on using Collectors.partitioningBy collector which would split the list into two parts by predicate value:
public void removeYear(int removeYear) {
Map<Boolean, Publication> partitioned = publicationList.stream()
.collect(Collectors.partitioningBy(p.getYear() == removeYear));
System.out.println("deleted publications: " + partitioned.get(true));
// keep publications without the removeYear
publicationList = partitioned.get(false);
}
I am trying to implement an algorithm in a special data structure in graph form. my goal ist to get all paths from leaf (Target element) to the root.
This is how the graph looks like the image below.
We need to remember all of the path that we had in order to traverse in all of the different ways on the graph, therefore only a states list isn't enough, we need a paths list. For every path we will make it longer by one if it has one parent and if it has two or more we will duplicate this list and add the parent to each one.
Well I am not great at Java and I can not run this code so I can't guarantee this will run but the algorithm is ok.
public static List<ARGState> getAllErrorStatesReversed(ReachedSet reachedSet) {
ARGState pIsStart =
AbstractStates.extractStateByType(reachedSet.getFirstState(), ARGState.class);
ARGState pEnd = targetStates.get(0);
List<List<ARGState>> results = new ArrayList<>();
List<List<ARGState>> paths = new ArrayList<>();
paths.add(new ArrayList<ARGState>(pEnd));
// This is assuming from each node there is a way to go to the start
// Go on until all the paths got the the start
while (!paths.empty()) {
// Expand the last path on your list
List<ARGState> curPath = paths.remove(paths.size() - 1);
// If there is no more to expand - add this path and continue
if (curPath.get(curPath.size() - 1) == pIsStart) {
results.append(curPath);
continue;
}
// Expand the path
Iterator<ARGState> parents = curPath.get(curPath.size() - 1).getParents().iterator();
// Add all parents
while (parentElement.hasNext()) {
ARGState parentElement = parents.next();
List<ARGState> tmp = new ArrayList<ARGState>(List.copyOf(curPath));
tmp.add(parentElement);
paths.add(tmp);
}
}
return results;
}
Hope you understand, more than welcome to ask.
Good Luck
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.
I've got a family class that pulls data from a postgres database. The class looks like something like this:
#Entity
public class Family(){
#Id
private long id;
private String firstName;
private String lastName;
private Long parentId;
private4 String familyPath;
private List<Family> children;
//getters and setters
In the database, I have their relation to each other stored as a period-delimited string. So for example, if Bob is the child of Sue, the tree column would look like: "bob.sue". This path is stored as part of the family object in the familyPath variable.
CLARIFICATION
familyPath is a path based on unique IDs for each row in the database. So a path may look like "1.2.3" where the last number is the current row.
"1.2.4" is another potential path. so rows with IDs 3 and 4 are children of 2, etc.
In my code I query the database for all family members in the data, so I have a set of every member of the family in the database. My goal is to generate a set of all family members as a hierarchical structure using this initial, flat set. So, in the end if I call getChildren on Bob, I get a list back containing Sue and any other children.
My Solution:
First, I iterate through my list of families, and find what I call the root members -- those at the top level of the family path -- and remove them into a separate list. So now I have a list of top level family members, an a list of everyone else.
Then, for each member in the top level list, I call the following recursive method:
private Family familyTree(Family root, List<Family> members) {
List<Family> children = new ArrayList<>();
for (Family f : members) {
if (isChildOf(f, root)) {
children.add(familyTree(f, resources));
}
}
root.setChildren(children);
return root;
}
private boolean isChildOf(Family a, Family b) {
String pCPath = a.getFamilyPath();
String pPPath = b.getFamilyPath();
return pCPath.indexOf('.') >= 0
&& pCPath.substring(0, pCPath.lastIndexOf('.')).equals(pPPath);
}
and save the output to a list. This generates the desired results.
My Question
However, I feel that this recursive method is very expensive (n^2). I'm thinking that there may be a more efficient way to generate this hierarchy using sets, maps and the Family object's familyPath variable, But i keep getting stuck in multiple iterative loops. Does anyone have any thoughts?
Option 1 - Single pass
private Family familyTree(Family root, List<Family> members) {
Map<Long, List<Family>> parentMap = new HashMap<>();
// Assuming root is not contained in members
root.children = new ArrayList<>();
parentMap.put(root.id, root.children);
// Assign each member to a child list
for (Family member : members) {
// Put the family member in the right child list
Long parentId = member.getParentId();
List<Family> parentChildren = parentMap.get(parentId);
if (parentChildren == null) {
parentChildren = new ArrayList<>();
parentMap.put(parentId, parentChildren);
}
parentChildren.add(member);
// Get or create the child list of the family member
List<Family> ownChildren = parentMap.get(member.id);
if (ownChildren == null) {
ownChildren = new ArrayList<>();
parentMap.put(member.id, ownChildren);
}
member.children = ownChildren;
}
return root;
}
private Long getParentId() {
// left as an exercise...
}
Option 1.b - Single pass over all members including roots
private List<Family> familyTree(List<Family> members) {
List<Family> roots = new ArrayList<>();
Map<Long, List<Family>> parentMap = new HashMap<>();
// Assign each member to a child list
for (Family member : members) {
// Put the family member in the right child list
Long parentId = member.getParentId();
if (parentId == null) {
// a root member
roots.add(member);
} else {
// a non-root member
List<Family> parentChildren = parentMap.get(parentId);
if (parentChildren == null) {
parentChildren = new ArrayList<>();
parentMap.put(parentId, parentChildren);
}
parentChildren.add(member);
}
// Get or create the child list of the family member
List<Family> ownChildren = parentMap.get(member.id);
if (ownChildren == null) {
ownChildren = new ArrayList<>();
parentMap.put(member.id, ownChildren);
}
member.children = ownChildren;
}
return roots;
}
Option 2 - Add a reference to the parent
Your Family class should have a private Family parent attribute. You will then be able to do a single query per family "level". That is:
get all children of Sue
get all children of people from (1) and assign them to the proper parent
etc.
Option 3 - Nested Set Model of Hierarchies
The database schema can be modified to retrieve whole sub-trees in a single query. The trick is to give each tree node a "left" and a "right" value. These values establish a range for the "left" and "right" values of a node's children.
Selecting a full tree can then be done like this:
SELECT child.id, ...
FROM family AS child, family AS parent
WHERE child.lft BETWEEN parent.lft AND parent.rgt
AND parent.id = 111
ORDER BY child.lft;
There are many other hierarchical operations which can be done very easily with such a schema. See this post and Joe Celko's Trees and Hierarchies in SQL for Smarties for more information.
Finally, your model only considers a single parent for each family member which seems strange.
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.