Looping through java recursive references - java

I was writing a simple linked list implementation and the corresponding Trigger class like this:
public class Trigger {
public static void main(String[] args) {
LinkedList lin = new LinkedList();
lin.add(3);
lin.add(4);
lin.add(5);
lin.display();
}
}
public class LinkedList {
Item startItem;
LinkedList() {
startItem = new Item();
}
public void add(Integer newValue) {
if(startItem.value == null) {
startItem.value = newValue;
return;
}
Item tempItem = new Item();
tempItem.value = newValue;
while(startItem.next != null) {
startItem = startItem.next;
}
startItem.next = tempItem;
}
public void display() {
while(true) {
System.out.println("\t"+ startItem.value);
if(startItem.next == null) {
break;
} else {
startItem = startItem.next;
}
}
}
class Item {
Integer value;
Item next;
Item() {
this.value = null;
this.next = null;
}
}
}
The problem is, only the last two additions are getting retained and the previous additions are discarded. This is (of course) because i keep changing the object that the reference startItem points to. My question is, given a recursive structure like this, what is the correct looping mechanism? I know that in a linked list, there is no need to get to the end of the list to perform addition. Linked list structure is used as a context to ask about looping through recursive structures. Thanks.

Your basic structure is correct. You just need to add one line before you start looping...
Item currentItem = startItem;
while(currentItem.next != null) {
currentItem = currentItem.next;
}
The only time the field startItem should be changed is in your first check if its value is null. It's reference should never be changed as it should always point to the start of the structure. Consider making it final to enforce this.

Related

Randomly Generate a Tree Structure Consisting of Objects with their Parents

I'm trying to randomly generate a tree structure of objects that look something like the following:
Branch parent = new Branch("Start");
Branch branch1 = new Branch(parent, "Branch 1");
Branch branch2 = new Branch(parent, "Branch 2");
Branch branch21 = new Branch(branch2, "Branch 2.1");
Branch branch22 = new Branch(branch2, "Branch 2.2");
I know how to create objects manually, and how to generate random numbers, and I've seen some stuff on randomly generating nodes for creating fractals, but I'm pretty lost all the sudden, as I've never had to programmatically generate objects before.
Any ideas as to where to start, or what technique to use would be appreciated.
Typically, when building such items it's good to have a designed in and out. Otherwise, you will find yourself having to support many methods of application to support the intended result.
Hope this helps!
Try something along the following :)
Branch start = new Branch();
CreateChildren(start);
const int ChildrenLimitCheck = 0;
private void CreateChildren(Branch parent) {
//Use a limit variable so that you can decrease, and if it's equal to a sepcific number(usually 0) exit.
int Limit = (int) (Math.random() * 5);
//Call the function that's recursive, inside of a function that isn't recursive. This gives you a clean way to interface with the recursive function without excessive lines of code in other areas
generateChildren(parent,Limit);
}
private void generateChildren(Branch parent,int limit) {
//Check to see if we've hit our minimum. If so, exit out of the logic
if(limit == ChildrenLimitCheck)
return;
//Specify the random number of branches created in this instance
int numberOfBranches = (int) (Math.random() * 5);
for (int i = 0; i < numberOfBranches; i++) {
Branch child = new Branch(parent);
parent.Children.Add(child);
//Depending on what you want to do, either pass i or pass limit. If you don't use limit, you can remove it from this function :)
//If you pass i, try doing:
//for (int i = numberOfBranches; i > 0; i--)
//So that you can eventually get down to 0, to automatically stop your recursive calls with the above return statement.
//Seems you just want to run a loop for xxx number of times. This will still grant that, but you won't have to guess the upper limit
//of numberOfBranches to exit on, and you'll be able to exit cleanly
//This may be what caused your stackoverflow error. For all recursive functions, you need an exit condition or it will run indefinately
generateChildren(child,--limit);
//generateChildren(child,i);
}
}
I do this quite often and I can definately help in some areas of efficiency.
Try logic similar to the following. Place a breakpoint at Console.Write to see depth. This is a C++ object oriented approach, which I personally prefer over LINQ for performance. I didn't fine tune this, so LINQ may be faster. But if you know what you're doing, you can significantly increase performance via custom methods and inheritance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication11
{
public class Branch
{
//Branch Name
public string BranchName { get; set; }
//Add depth
public List<Branch> Children = new List<Branch>();
//Add a parent
public Branch Parent = null;
public Branch()
{
}
public Branch(string BranchName)
{
this.BranchName = BranchName;
}
public Branch(Branch Parent, string BranchName)
{
this.Parent = Parent;
this.BranchName = BranchName;
}
//Internal Functions
public bool HasParent()
{
return this.Parent != null;
}
public Branch getParent()
{
return this.Parent;
}
}
//Wrap a list inside of a class so we can have leverage over the add, and create our own functions for our need
public class BranchList
{
public List<Branch> branchParentList = new List<Branch>();
public void AddBranchToParent(Branch parent, Branch child)
{
foreach (Branch node in branchParentList)
{
if (node == parent)
{
node.Children.Add(child);
}
}
}
public void AddBranchAsChild(string parent, Branch child)
{
foreach (Branch node in branchParentList)
{
if (node.BranchName == parent)
{
node.Children.Add(child);
return;//Exit out, don't do the other loop. We found it
}
//Depth
AddBranchAsChildInChildren(node, child,parent);
}
}
public void AddBranchAsChildInChildren(Branch branch,Branch Child,string parent)
{
foreach(Branch child in branch.Children)
{
if (child.BranchName == parent)
child.Children.Add(Child);
}
}
public void AddBranchAsChildInChildren(Branch branch, string Child, string parent)
{
foreach (Branch child in branch.Children)
{
if (child.BranchName == parent)
child.Children.Add(new Branch() { BranchName=Child });
}
}
public void AddBranchAsChild(string parent, string child)
{
foreach (Branch node in branchParentList)
{
if (node.BranchName == parent)
{
node.Children.Add(new Branch() { BranchName = child });
return;
}
//Depth
AddBranchAsChildInChildren(node, child, parent);
}
}
public void AddBranchAsParent(Branch Branch, Branch Child)
{
if (branchParentList.Contains(Branch) == false)
throw new Exception("Parent exists");
foreach (Branch b in branchParentList)
{
if (b == Child)
{
b.Parent = Branch;
}
}
}
public void AddParent(Branch Parent)
{
if (branchParentList.Contains(Parent))
throw new Exception("Parent exists");
this.branchParentList.Add(Parent);
}
}
//Wrap the list, use it as an interface
public class BranchManager
{
public BranchList branchList = new BranchList();
public BranchManager()
{
}
public void AddParent(Branch Branch)
{
branchList.AddParent(Branch);
}
public void AddBranchAsChild(Branch Parent, Branch Child)
{
branchList.AddBranchToParent(Parent, Child);
}
public void AddBranchAsChild(string ParentName, Branch Child)
{
branchList.AddBranchAsChild(ParentName, Child);
}
public void AddBranchAsChild(string ParentName, string ChildName)
{
branchList.AddBranchAsChild(ParentName, ChildName);
}
}
class Program
{
static void Main(string[] args)
{
/*
Branch parent = new Branch("Start");
Branch branch1 = new Branch(parent, "Branch 1");
Branch branch2 = new Branch(parent, "Branch 2");
Branch branch21 = new Branch(branch2, "Branch 2.1");
Branch branch22 = new Branch(branch2, "Branch 2.2");
*/
BranchManager branchManager = new BranchManager();
branchManager.AddParent(new Branch("Start"));
branchManager.AddBranchAsChild("Start", "Branch 1");
branchManager.AddBranchAsChild("Start", "Branch 2");
branchManager.AddBranchAsChild("Branch 2", "Branch 2.1");
branchManager.AddBranchAsChild("Branch 2", "Branch 2.2");
Console.WriteLine(branchManager.branchList.branchParentList.Count);
}
}
}
Best guess so far, using a recursive function to handle the randomly generating children & parents:
Branch start = new Branch();
generateChildren(start);
private void generateChildren(Branch parent) {
int numberOfBranches = (int) (Math.random() * 5);
for (int i = 0; i < numberOfBranches; i++) {
Branch child = new Branch(parent);
generateChildren(child);
}
}
It properly creates a list of Branch objects with linked parents. I ran into a StackOverflow error until I wrapped it in a counter that limits the total number of branches.
The real question is: Is there a non-recursive way to handle it?

cannot count the size of an arraylist which contains two arrayllists

I hope I can explain my question clearly:
There are three classes.
Class Lamboghini which is getting modelYear, modelName, horsepower, and boolean.
Class LamboghiniCarLot which has an arraylist inventory(add some lamboghini elements to it).
Class LamboghiniDealershipGroup which has arraylist carLots.
Now, in LamboghiniDealershipGroup class, I try to make a method public int getTotalInventoryCount();however, I cannot count the inventory correctly. My output always been 0. I think it might be because the way I added to arraylist is wrong. But I don't know how to fix this problem.
public Lamborghini(int modelYear, String modelName, double horsepower, boolean isRearWheelDrive)
{
setModelYear(modelYear);
setModelName(modelName);
setHorsepower(horsepower);
setIsRearWheelDrive(isRearWheelDrive);
}
public class LamborghiniCarLot
{
private String lotName;
private ArrayList<Lamborghini> inventory;
/**
* creates the inventory ArrayList object;
* the inventory remains empty (no Lamborghini objects are added when this constructor is called)
*/
public LamborghiniCarLot()
{
inventory = new ArrayList<Lamborghini>();
}
/**
* An example of a method - replace this comment with your own
*
* #param y a sample parameter for a method
* #return the sum of x and y
*/
public LamborghiniCarLot(String lotName)
{
setLotName(lotName);
inventory = new ArrayList<Lamborghini>();
inventory.add(new Lamborghini(1965, "350GT", 365.3, true));
inventory.add(new Lamborghini(1966, "400GT 2+2", 366.3, false));
inventory.add(new Lamborghini(1967, "MIURA", 367.3, true));
inventory.add(new Lamborghini(1968, "espada", 368.3, false))
}
public void setLotName(String lotName)
{
if(lotName != null)
{
if(lotName.equals("Taylor's Used Lambos"))
{
this.lotName = "Jason's Used Lambos";
}else
{
this.lotName = lotName;
}
}
}
public void addLamborghini(Lamborghini newLamborghini)
{
if(inventory != null && newLamborghini != null && inventory.size() > 0)
{
for(Lamborghini lambo : inventory)
{
if(lambo == null)
{
inventory.add(newLamborghini);
}
}
}
}
public ArrayList<Lamborghini> getInventory()
{
return inventory;
}}
then, the third class.
public LamborghiniDealershipGroup(String dealershipGroupName)
{
setDealershipGroupName(dealershipGroupName);
carLots = new ArrayList<LamborghiniCarLot>();
//Create the first car lot
LamborghiniCarLot carlot1 = new LamborghiniCarLot();
carlot1.setLotName("Jason's vintage lambos.");
carlot1.addLamborghini(new Lamborghini(1965, "350GT", 365.3, true));
carlot1.addLamborghini(new Lamborghini(1966, "400GT 2+2", 366.3, false));
carlot1.addLamborghini(new Lamborghini(1967, "MIURA", 367.3, true));
//Create the second car lot
LamborghiniCarLot carlot2 = new LamborghiniCarLot();
carlot2.setLotName("Taylor's brand new lambos.");
carlot2.addLamborghini(new Lamborghini(2006, "gallardo", 506.3, true));
carlot2.addLamborghini(new Lamborghini(2007, "gallardo", 507.3, true));
//Add them to the arraylist
carLots.add(carlot1);
carLots.add(carlot2);
}
and my method is here:
public int getTotalInventoryCount()
{
int count = 0;
for(LamborghiniCarLot c : carLots)
{
count += c.getInventory().size();
}
return count;
}
the method always get int 0. How can i fix it?
This is very strange:
public void addLamborghini(Lamborghini newLamborghini) {
if (inventory != null && newLamborghini != null && inventory.size() > 0) {
for (Lamborghini lambo : inventory) {
if (lambo == null) {
inventory.add(newLamborghini);
}
}
}
}
Let's rattle off the conditions.
If inventory isn't null...
...and newLamborghini isn't null...
...and there's at least one item in the inventory...
Then we iterate over all items in the inventory.
If one of those items is null...
...we add the newLamborghini into the inventory.
Almost all of this is unnecessary, and this is the chief reason why you're not inserting anything - your collection starts empty. Even if it weren't, you don't add any null elements to it to satisfy the inner foreach loop.
You can reduce this to a saner check to see if the elements you're inserting are null and if the collection you're inserting it into is null instead.
if(inventory != null && newLamborghini != null) {
inventory.add(newLamborghini);
}
If you eagerly initialized your inventory collection (by writing ArrayList<Lamborghini> inventory = new ArrayList<>();), you could eschew the null check on inventory.
You should add two below methods in your LamborghiniCarLot class. And it should work.
public void setLotName(String lotName) {
this.lotName = lotName;
}
public void addLamborghini(Lamborghini lamborghini) {
inventory.add(lamborghini);
}

do-while with Java8-Optional

I'm frequently using the do-while-checkNextForNull-getNext looping pattern (don't know if there is an official name for it) in some of my projects. But in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code. But when using Optional in this looping pattern, the code gets a bit verbose and ugly, but because Optional has some handy methodS, I would expect that there must exist a cleaner way than the one I came up with below.
Example:
Given the following class.
class Item {
int nr;
Item(nr) {
this.nr = nr;
// an expensive operation
}
Item next() {
return ...someCondition....
? new Item(nr + 1)
: null;
}
}
In which the first item always has nr==1 and each item determines the next item, and you don't want to create unnecessary new items.
I can use the following looping do-while-checkNextForNull-getNext pattern in client-code:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next()) != null);
With Java8-Optional, the given class becomes:
class Item {
....
Optional<Item> next() {
return ...someCondition....
? Optional.of(new Item(nr + 1))
: Optional.empty();
}
}
And then the do-while-checkNextForNull-getNext looping pattern becomes a bit ugly and verbose:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next().orElse(null)) != null);
The orElse(null)) != null part feels uncomfortable.
I have looked for other kind of loops, but haven't found a better one. Is there a cleaner solution?
Update:
It is possible to use a for-each loop while at the same time avoiding null-references (the use of null-references is considered as a bad practice). This solution has been proposed by Xavier Delamotte, and doesn't need Java8-Optional.
Implementation with a generic iterator:
public class Item implements Iterable<Item>, Iterator<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public Item next() {
return new Item(nr + 1);
}
public boolean hasNext() {
return ....someCondition.....;
}
#Override
public Iterator<Item> iterator() {
return new CustomIterator(this);
}
}
and
class CustomIterator<T extends Iterator<T>> implements Iterator<T> {
T currentItem;
boolean nextCalled;
public CustomIterator(T firstItem) {
this.currentItem = firstItem;
}
#Override
public boolean hasNext() {
return currentItem.hasNext();
}
#Override
public T next() {
if (! nextCalled) {
nextCalled = true;
return currentItem;
} else {
currentItem = currentItem.next();
return currentItem;
}
}
}
Then client code becomes very simple/clean:
for (Item item : new Item(1)) {
// do something with the item ....
}
Although this may be seen as a violation of the Iterator contract because the new Item(1) object is included in the loop, whereas normally, the for loop would immediately call next() and thus skipping the first object. In other words: for the first object, next() is violated because it returnS the first object itself.
You can do something like this :
Optional<Item> item = Optional.of(new Item(1));
do {
Item value = item.get();
// do something with the value ....
} while ((item = value.next()).isPresent());
or (to avoid the extra variable) :
Optional<Item> item = Optional.of(new Item(1));
do {
// do something with item.get() ....
} while ((item = item.get().next()).isPresent());
in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code
No, it is the other way around: Optional can be used where it helps write cleaner code. Where it doesn't, just stick to the old idiom. Do not feel any pressure to use it if your existing idiom looks fine—and it does, in my opinion. As an example, this would be good usage of the Optional:
item.next().map(Object::toString).ifPresent(System.out::println);
Since you need to break out of the loop on the first non-present Optional, this doesn't really help.
However, I assume your true interest is more general: leveraging the features of Java 8 for your code. The abstraction you should pick is the Stream:
itemStream(() -> new Item(1)).forEach(item -> { ... all you need ... });
And, naturally, you can now go wild with stream processing:
itemStream(() -> new Item(1)).filter(item.nr > 3).mapToInt(Item::nr).sum();
This is how you would construct the stream:
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class ItemSpliterator extends Spliterators.AbstractSpliterator<Item>
{
private Supplier<Item> supplyFirst;
private Item lastItem;
public ItemSpliterator(Supplier<Item> supplyFirst) {
super(Long.MAX_VALUE, ORDERED | NONNULL);
this.supplyFirst = supplyFirst;
}
#Override public boolean tryAdvance(Consumer<? super Item> action) {
Item item;
if ((item = lastItem) != null)
item = lastItem = item.next();
else if (supplyFirst != null) {
item = lastItem = supplyFirst.get();
supplyFirst = null;
}
else return false;
if (item != null) {
action.accept(item);
return true;
}
return false;
}
public static Stream<Item> itemStream(Supplier<Item> supplyFirst) {
return StreamSupport.stream(new ItemSpliterator(supplyFirst), false);
}
}
With this you are a tiny step away from the ability to seamlessly parallelize your computation. Since your item stream is fundamentally sequential, I suggest looking into my blog post on this subject.
Just add the loop support to your API:
class Item {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public void forEach(Consumer<Item> action) {
for(Item i=this; ; i=new Item(i.nr + 1)) {
action.accept(i);
if(!someCondition) break;
}
}
public Optional<Item> next() {
return someCondition? Optional.of(new Item(nr+1)): Optional.empty();
}
}
Then you can simply iterate via lambda expression
i.forEach(item -> {whatever you want to do with the item});
or method references
i.forEach(System.out::println);
If you want to support more sophisticated operations than just forEach loops, supporting streams is the right way to go. It’s similar in that your implementation encapsulates how to iterate over the Items.
Dropping another alternative here that is available since Java 9.
Stream.iterate(new Item(1), Item::hasNext, Item::next)
.forEach(this::doSomething)
Where doSomething(Item item) is the method that does something with the item.
Since this is related to some kind of design i come up with below design.
Create interface which support to provide optional next.
public interface NextProvidble<T> {
Optional<T> next();
}
Item implement NextProvidble interface.
public class Item implements NextProvidble<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
#Override
public Optional<Item> next() {
return /*...someCondition....*/ nr < 10 ? Optional.of(new Item(nr + 1)) : Optional.empty();
}
#Override
public String toString() {
return "NR : " + nr;
}
}
Here i use /...someCondition..../ as nr < 10
And new class for Custom Do While as below.
public abstract class CustomDoWhile<T extends NextProvidble<T>> {
public void operate(T t) {
doOperation(t);
Optional<T> next = t.next();
next.ifPresent( nextT -> operate(nextT));
}
protected abstract void doOperation(T t);
}
Now what you have to done in your client code.
new CustomDoWhile<Item>() {
#Override
protected void doOperation(Item item) {
System.out.println(item.toString());
}
}.operate(new Item(1));
It may very clear.
Please add your thoughts.

Copy constructor questions about Java

I have a question on copy construction in Java. Consider the following class;
In the copy constructor I can say new(Integer(other.id)) to get a new integer object being passed to the constructor, but I can't say new T(other.data) as the compiler will say cannot instantiate the type T. How can I make sure that when the generic item is copy constructed that it will not just pass a reference such that the 2 objects will share the underlying data.
Also, in the getLinks method it is doing a new and creating a new object of the list but is that going to deep copy and create new object of the items contained in the list or will it just contain references to the existing objects list items such that you have 2 lists both pointing to the same data. See below the comments / code. Thanks in advance for your expertise.
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
other.id = new Integer(other.id);
other.data = other.data; // line in question
this.links=other.getLinks(); // also will create a new list with references
// or will it deep copy the items contained in the list?
// see getLinks() method below
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
return new ArrayList<DigraphNode<T> >(links);
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}
You can't instantiate new T(other.data) as you tried, but you can clone() other.data if T implements Cloneable
Every call to getLinks() will create a new list with reference to object contained to links, you have to different lists with same reference inside (so change one reference object property will reflect to other list object because they are the same object)
About ArrayList<> links = new ArrayList<>(); from Oracle doc:
Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:
{
// whatever code is needed for initialization goes here
}
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of
code between multiple constructors.
EDIT:
You can define a static method (copy) that try to use all possible strategies to copy generic object; the best approch is to define your own interface to separate your own stategy and simulate a sort of copy-constructor (you can reuse copy method if you want), else via serialization or, as last try, using cloning (but clone() is full of pitfall).
You can also use this libraries:
Cloning
Commons-SerializationUtils
interface MyCloneableInterface<T> {
T duplicate(T object) throws CopyException;
}
public static <T> T copy(T data) throws CopyException {
if(data == null) return null;
if(data instanceof MyCloneableInterface) {
return ((MyCloneabeInterface)data).duplicate(data);
}
if(data instanceof Serializable) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (CloneExample) ois.readObject();
}
catch(...) {//rethrow}
}
if(data instanceof Cloneable) {
try {
return (T)data.clone();
}
catch(CloneNotSupportedException e) {//rethrow}
}
// else you can look for copy-constructor via reflection or
// cloning object field-by-field via reflection...
}
First Question: You cannot instantiate a generic instance (in other words call T's constructor). You should either define T implements Cloneable and call clone or use another interface of your own if T is always under your control. There are many pitfalls to this method, I'd suggest you first read about this interface and familiarize yourself with the pitfalls (you can find a great chapter on this, in "Effective Java" book). Also, it is not always that you can guarantee that this class will use T types which are Cloneable.
About links - you're instantiating it in the beginning and then override it in the constructor - Why? Remove the initialization. The way your getLinks works is not by creating a deep copy. Meaning - you'll get a new list, the list itself will be different from the original list, but the items will be shallow copies.
About your last question - as I already said, it's redundant. Remove the initialization at the beginning. You're creating an object, never use it and leave it for garbage collection. What you can do to avoid calling this in every constructor is something like this:
public DigraphNode() {
links = new ArrayList<DigraphNode<T> >();
}
And have other constructors call this constructor, for example:
public DigraphNode(T val) {
this();
this.data = val;
}
Upvoted all helpful answers, but I am answering my own question below which shows the updated code. I wanted to see how someone would implement a copy for a generic but no one posted code for that so I rolled my own. See below my answer.
import java.lang.reflect.*;
import java.util.*;
class MissingDigraphNodeException extends Exception
{
private static final long serialVersionUID = 1000L;
public MissingDigraphNodeException(String message)
{
super(message);
}
}
class CopyException extends Exception
{
private static final long serialVersionUID = 2000L;
public CopyException(String message)
{
super(message);
}
}
class DigraphNode<T>
{
Integer id;
T data;
ArrayList<DigraphNode<T> > links;
public DigraphNode(Integer i)
{
id = i;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(Integer i, T d)
{
id = i; data = d;
links = new ArrayList<DigraphNode<T> >();
}
public DigraphNode(DigraphNode<T> other)
{
try
{
this.data = copy(other.data);
}
catch (CopyException e)
{
e.printStackTrace();
}
this.links=other.getLinks();
this.id = new Integer(other.id);
}
// is there a better way to copy a generic?
#SuppressWarnings("unchecked")
public T copy( T source ) throws CopyException
{
Class<?> clzz = source.getClass();
Method meth;
Object dupl = null;
try {
meth = clzz.getMethod("clone", new Class[0]);
dupl = meth.invoke(source, new Object[0]);
} catch (Exception e)
{
e.printStackTrace();
throw new CopyException("Error: Copying Generic of T");
}
return (T) dupl;
}
public void setData (T d ) { data = d; }
public void addLink (DigraphNode<T> n) { links.add(n); }
public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }
public ArrayList<DigraphNode<T> > getLinks()
{
// return a new copy of the list
ArrayList<DigraphNode<T> > l = new ArrayList<DigraphNode<T> >();
for ( DigraphNode<T> i : links )
{
i.links.add(new DigraphNode<T>(i)); // use copy constructor
}
return l;
}
public void printNode()
{
System.out.print("Id: " + id + " links: ");
for ( DigraphNode<T> i : links )
{
System.out.print(i.id + " ");
}
System.out.println();
}
}

Get children with Lucene's TaxonomyReader

In Lucene, I am using the TaxonomyReader to read an index of a taxonomy stored in my disk. For a given category, I need to find all categories that are its children. However, in the Lucene's API I could find a method to retrieve the parent but not with the children. There is a method called getChildrenArrays() that returns a ChildrenArrays object. As you can see, this class only has two methods:
getYoungestChildArray
getOlderSiblingArray
I want to implement Enumerator using these two methods. Does someone know how to do it?
I got the following:
private class EnumChildren implements Enumeration<Integer> {
int category, current;
int[] next, first;
public EnumChildren(int category) {
ChildrenArrays childrenArrays = tr.getChildrenArrays();
first = childrenArrays.getYoungestChildArray();
next = childrenArrays.getOlderSiblingArray();
current = first[category];
}
public boolean hasChildren() {
return (current != TaxonomyReader.INVALID_ORDINAL);
}
#Override
public boolean hasMoreElements() {
current = next[current];
return (current != TaxonomyReader.INVALID_ORDINAL);
}
#Override
public Integer nextElement() {
return current;
}
}
Ans is used as:
ordinal = tr.getOrdinal(new CategoryPath(nodeCategory.getPath(), '/'));
EnumChildren childrenEnumeration = new EnumChildren(ordinal);
if (childrenEnumeration.hasChildren()) {
do {
int current = childrenEnumeration.nextElement();
Category child = new Category(tr.getPath(current).toString());
addChildren(child);
nodeCategory.children.add(child);
} while (childrenEnumeration.hasMoreElements());
}

Categories

Resources