I am trying to write a class that implements a tree using an array and I need some help to write an Iterator method that which returns an iterator of the elements stored in the tree.
Solution:
public Iterator<E> iterator() {
return new Iterator<E>() {
private int index = 0;
public boolean hasNext() {
return index < ArrayTree.this.size();
}
public E next() {
if (!hasNext()) {
return new NoSuchElementException();
}
return ArrayTree.this.tree[index++];
}
public void remove() {
return new OperationNotSupported();
}
}
}
Without examining your implementation very closely, a very simple implementation might be
public Iterator<E> iterator() {
return new Iterator<E>() {
private int index = 0;
public boolean hasNext() {
return index < ArrayTree.this.size();
}
public E next() {
if (!hasNext()) {
return new NoSuchElementException();
}
return ArrayTree.this.tree[index++];
}
public void remove() {
return new OperationNotSupported();
}
}
}
There are a couple of ways to go, but if your ArrayTree class implements Iterable and Iterator interfaces you'll be on your way.
Related
I'm working in a school project, where I want to implement the Iterator design pattern. I want to use generic arrays.
Container.java
public interface Container {
Iterator getIterator();
}
Iterator.java
public interface Iterator <T> {
boolean hasNext();
T next();
}
TransactionRepository.java
public class TransactionRepository<T> implements Container {
public TransactionRepository(){
userTransactions = new ArrayList<>();
}
public List<T> userTransactions;
#Override
public Iterator <T> getIterator() {
return new UserTransactions();
}
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
private class UserTransactions implements Iterator <T> {
int index;
#Override
public boolean hasNext() {
return index < userTransactions.size();
}
#Override
public T next() {
if(this.hasNext())
return userTransactions.get(index);
return null;
}
}
}
In my other class, I add the elements to the list by first creating the TransactionRepository object like this: TransactionRepository<String> companyName = new TransactionRepository<String>();.
Then I add elements to the array with the add method companyName.add("CompanyName");. After that I want to print the array using Iterator, but It just won't print the elements. I have tried multiple variations, but none of them worked.
Iterator <String> stringIterator = companyName.getIterator();
while (stringIterator.hasNext()) {
System.out.println("Name : " + companyName.get());
}
With the current implementation List<T> userTransactions is never updated.
In this case userTransactions.size() in hasNext() method will always return 0 so the result of method will be false.
Moreover, you should use stringIterator.next() instead of companyName.get(). Since you implement your own iterator you don't want to use get() method at all.
There is also a need to update index counter variable after calling next() method.
#Override
public T next() {
if (this.hasNext())
return userTransactions.get(index++);
return null;
}
Change modifier on userTransactions to private final as it should be referenced just with iterator.
Code with proposed improvements:
public class TransactionRepository<T> implements Container {
public TransactionRepository() {
userTransactions = new ArrayList<>();
}
public List<T> userTransactions;
#Override
public Iterator<T> getIterator() {
return new UserTransactions();
}
public void add(T t) {
userTransactions.add(t);
}
private class UserTransactions implements Iterator<T> {
int index;
#Override
public boolean hasNext() {
return index < userTransactions.size();
}
#Override
public T next() {
if (this.hasNext()) {
return userTransactions.get(index++);
}
return null;
}
}
}
It seems that you are never adding elements to your userTransactions List on the add method
You add() method doesnt add anything to your list , it's just like a setter of the attribute t , you should use it to add elements to the list instead
public void add(T t) {
userTransactions.add(t);
}
There is also another problem , the index , your next() method gets the index element while you didnt initialise your index variable , i recommand you to do it in this way :
int index = 0 ;
...
public T next() {
if(this.hasNext())
int temp = index;
index++;
return userTransactions.get(temp);
return null;
}
I have generic class MyArray where private member is ArrayList, and inside is implemented iterator.
In Main is given some MyArray with strings and I want to delete all "test" from it... Problem is in iterator which method remove doesn't work
Here is how class looks like:
public class MyArray<E> {
private ArrayList<E> list;
public MyArray() {
list = new ArrayList<E>();
}
public int length() { return list.size(); }
public E at(int pos) { return list.get(pos); }
public void add(E val) { list.add(val); }
public void remove(int pos) { list.remove(pos); }
public class MyIterator implements Iterator<E>{
int index;
#Override
public boolean hasNext() {
return index < list.size();
}
#Override
public E next() {
if (!hasNext())
throw new NoSuchElementException("no next value");
E tmp = list.get(index);
index++;
return tmp;
}
}
public Iterator<E> iterator() {
return new MyIterator();
}
public static void main(String[] args) {
MyArray<String> b = new MyArray<String>();
b.add("This");
b.add("is");
b.add("test");
b.add("please");
b.add("delete");
b.add("all");
b.add("test");
Iterator<String> iter = b.iterator();
while(iter.hasNext())
System.out.println(iter.next());
for(Iterator<String> i = b.iterator(); i.hasNext(); ) {
String tmp = i.next();
if (tmp.equals("test"))
i.remove();
}
Iterator<String> ite = b.iterator();
while(ite.hasNext())
System.out.println(ite.next());
}
}
Exception that I get is:
Exception in thread "main" java.lang.UnsupportedOperationException: remove
at java.util.Iterator.remove(Unknown Source)
at cas1.MyArray.main(MyArray.java:71)
You need to override remove() in your Iterator.
However, it'd be easiest to make your iterator() method return list.iterator(), rather than implementing it yourself:
public Iterator<E> iterator() {
return list.iterator();
}
Iterator in an interface, and you need to implement each of the Iterator methods in MyIterator that you intend to call.
MyIterator that you defined doesn't override Iterator.remove() and
the remove() defined in the Iterator interface is defined as a default method that throws UnsupportedOperationException :
default void remove() {
throw new UnsupportedOperationException("remove");
}
So override it simply to remove effectively the iterated element.
You can rely on ArrayList.Itr code :
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
I am trying to figure out how Guava is creating the iterator that cycles infinitely over itself but I cannot figure it out.
public static <T> Iterable<T> cycle(final Iterable<T> iterable) {
checkNotNull(iterable);
return new FluentIterable<T>() {
#Override
public Iterator<T> iterator() {
return Iterators.cycle(iterable);
}
#Override public String toString() {
return iterable.toString() + " (cycled)";
}
};
}
public static <T> Iterator<T> cycle(final Iterable<T> iterable) {
checkNotNull(iterable);
return new Iterator<T>() {
Iterator<T> iterator = emptyIterator();
Iterator<T> removeFrom;
#Override
public boolean hasNext() {
if (!iterator.hasNext()) {
iterator = iterable.iterator();
}
return iterator.hasNext();
}
#Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
removeFrom = iterator;
return iterator.next();
}
#Override
public void remove() {
checkRemove(removeFrom != null);
removeFrom.remove();
removeFrom = null;
}
};
}
However it does not show how exactly this is achieved. I am missing something probably.
This part of code
if (!iterator.hasNext()) {
iterator = iterable.iterator();
}
checks if old iterator has no more elements. When this is true it simply gets new iterator which will let us start again.
Flatten an iterator of iterators in Java. If the input is [ [1,2], [3,[4,5]], 6], it should return [1,2,3,4,5,6]. Implement hasNext() and next(). Be careful when the inner iterator or list is empty.
I don't think my code works for multiple levels of inner lists.
public class FlattenList {
int index = 0; // keep an index to indicate where the current accessed element is
List<Integer> flattenedList = new ArrayList<>(); // flattenedList
public FlattenList(List<List<Integer>> lists){
for(List<Integer> list : lists){ // add all inner list to our underlying list.
flattenedList.addAll(list);
}
}
public boolean hasNext(){ // check if the index has exceeded the list size
return flattenedList.size() > index? true : false;
}
public Integer next(){ // return the next element, and increment the index
Integer result = flattenedList.get(index);
index++;
return result;
}
}
So basically this is like writing a depth first traversal of a tree. Leaf nodes of this tree are numbers, all interior nodes are modeled as Iterators. Here is some pseudo code:
void flatten(Iterator<Object> iterator, List<Integer> flattenedList) {
for (Object o : iterator) {
if (o instanceof Iterator) {
flatten((Iterator) o, flattenedList);
} else {
flattenedList.add((Integer) o);
}
}
}
Here, I'll start it for you:
public <T> Iterator<T> flatten(final Iterator<Iterator<T>> iterators) {
if (iterators == null) {
throw new IllegalArgumentException("iterators can't be null");
}
return new Iterator<>() {
#Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented: hasNext");
}
#Override
public T next() {
throw new UnsupportedOperationException("Not implemented: next");
}
};
}
Now you just do that pesky brainwork and you'll be done.
EDIT
If you're not used to that syntax, here's a slightly easier one:
public <T> Iterator<T> flatten(final Iterator<Iterator<T>> iterators) {
return new MyFlatteningIterator<>(iterators);
}
public class MyFlatteningIterator<T> implements Iterator<T> {
private final Iterator<Iterator<T>> iterators;
public MyFlatteningIterator(final Iterator<Iterator<T>> iterators) {
if (iterators == null) {
throw new IllegalArgumentException("iterators can't be null");
}
this.iterators = iterators;
}
#Override
public boolean hasNext() {
throw new UnsupportedOperationException("Not implemented: hasNext");
}
#Override
public T next() {
throw new UnsupportedOperationException("Not implemented: next");
}
}
You should not treat this as a list, rather as Jon stated this is more suitable when you are talking about trees. If you infect looking for a solution to get a flatted iterator of list of lists (something that looks like [[1],[1,2,3],[8,9]]) then I think that the following solution will work better
import java.util.Collection;
import java.util.Iterator;
public class FlattedIterator<T> implements Iterator<T> {
private Iterator<T>[] iteratorsArray;
public FlattedIterator(Collection<T>[] items) {
this.iteratorsArray = new Iterator[items.length];
for(int index = 0; index < items.length; index++) {
this.iteratorsArray[index] = items[index].iterator();
}
}
#Override
public boolean hasNext() {
boolean hasNext = false;
for(int index = 0; index < this.iteratorsArray.length; index++) {
hasNext |= this.iteratorsArray[index].hasNext();
}
return hasNext;
}
#Override
public T next() {
int index = 0;
while(index < this.iteratorsArray.length && !this.iteratorsArray[index].hasNext()) {
index++;
}
if(index >= this.iteratorsArray.length ) {
throw new IndexOutOfBoundsException("Reached end of iterator");
}
return this.iteratorsArray[index].next();
}
}
Bear in mind that the reason that I think this solution will work better is due to the fact that in your solution you initialized flattenedList by adding all the data from the given lists meaning that if in some point of the program one of those lists will received more data after you initialized FlattenList then the new data wont appear while you read the iterator.
The list over which I want to iterate, contains an Array.
What I am trying to do is to make it possible to create an Iterator within the Iterator, so that I am able to iterate over the array in every Listelement.
I tried it this way:
#Override
public Iterator<A> iterator() {
return new MyListIterator();
}
private class MyListIterator implements Iterator<A>, Iterable<B>
{
private Listelem current;
private MyListIterator()
{
this.current = head;
}
#Override
public boolean hasNext()
{
return this.current != null;
}
#Override
public A next()
{
A next = this.current.getValue();
this.current = this.current.getSuccessor();
return next;
}
#Override
public void remove()
{
Listelem tmp = head;
while( tmp.getSuccessor().getSuccessor() != this.current )
{
tmp = tmp.getSuccessor();
}
tmp.setSuccessor(this.current);
}
#Override
public Iterator<B> iterator() {
return new MyInnerListIterator();
}
private class MyInnerListIterator implements Iterator<B>
{
private int currentIndex = 0;
private B[] array = current.getAssoc();
#Override
public boolean hasNext() {
return currentIndex < array.length && array[currentIndex] != null;
}
#Override
public B next() {
return array[currentIndex++];
}
#Override
public void remove() {
}
}
}
The problem is, when I am creating the first Iterator with iterator() the object does not contain the method iterator().
Can somebody explain to my why this is not working, and how to do it different?
The problem is that iterator returns an Iterator, even though in this case it happens to also be a MyListIterator. Class Iterator does not have an iterator() function. You need to have iterator() return a MyListIterator, so that you can use methods not in the Iterator interface.
It is likely simpler however, to simply use a for:in loop:
List<Object[]> list = ....
for (Iterator<Object[]> it = list.iterator(); it.hasNext();) {
Object[] arr = it.next();
for (Object o : arr) {
...
}
}
And if you don't need to remove elements from the list, then you can replace the iterator use with another for:in