I need to implement my own Iterator for my List class that functions like a Stack and implements java.lang.Iterable.
The Iterator method that is implemented in the List class should return an Iterator.
#Override
public Iterator<E> iterator() {
return new Iterator<>() {
private MyEntry<E> it = begin;
#Override
public boolean hasNext() {
if(pos.next != null) {
return true;
}
else {
return false;
}
}
#Override
public E next() {
if (!hasNext()) {
reset();
}
else {
it = it.next;
}
return it.o;
}
#Override
public void remove() {
}
};
}
The List itself works like a Stack. It has an begin Entry that marks the beginning of the List. Each Entry holds a reference to the next Entry. With the pos Element the List keeps track of its position. The advance() method allows you to pass through the list Entry by Entry. The elem() method returns the Value that the Entry holds at the position pos. The add() method adds an Entry at the end of the List. The delete() method removes the Entry at pos.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyList<E> implements Cloneable, java.lang.Iterable {
public MyList() {
pos = begin = new MyEntry<E>();
}
public boolean empty() {
return begin.next == null;
}
public boolean endpos() { // true, if end has been reached
return pos.next == null;
}
public void reset() {
pos = begin;
}
public void advance() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
pos = pos.next;
}
public E elem() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
return pos.next.o;
}
public void add(E x) {
MyEntry<E> newone = new MyEntry<E>(x, pos.next);
pos.next = newone;
}
public void delete() {
if (endpos()) {
throw new NoSuchElementException("Already at the end of this List");
}
pos.next = pos.next.next;
}
The Entrys that the List holds have a Generic Value o and a reference next tho the next MyEntry
class MyEntry<E> {
MyEntry<E> next;
E o;
MyEntry() {
this(null, null);
}
MyEntry(E o) {
this(o, null);
}
MyEntry(E o, MyEntry<E> e) {
this.o = o;
this.next = e;
}
}
But at the moment when I am testing it with my test class MyListTest I get the three test Strings out, but after that the Programm throws an NullPointerException in the next() method at return it.o
import org.junit.Test;
import java.util.*;
public class MyListTest {
#Test
public void test() {
MyList list = new MyList();
Iterator itr = list.iterator();
list.add("a");
list.add("b");
list.add("c");
while(itr.hasNext()) {
Object element = itr.next();
System.out.println(element + " ");
}
iter.remove();
while(itr.hasNext()) {
Object element = itr.next();
System.out.println(element + " ");
}
}
}
My Question is why the Iterator runs out of bounds after the last Entry and how I can prevent that.
So the Solution was that the hasNext() method
#Override
public boolean hasNext() {
if(pos.next != null) {
return true;
}
else {
return false;
}
}
Should have been
#Override
public boolean hasNext() {
if(it.next != null) {
return true;
}
else {
return false;
}
}
Because neither hasNext() nor next() should interfere with the pos element.
The Iterator should keep its own position independent from the rest of the class.
Related
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();
}
}
public static void main (String[] args)
{
Student st1 = new Student("Adams", 3.6, 26);
Student st2 = new Student("Jones", 2.1, 29);
Student st3 = new Student("Marcus", 4.0, 53);
System.out.println("Testing non-recursive code");
LinkedListStud LL = new LinkedListStud();
//checks if linked list is empty
System.out.println("Linked list is empty?: " + LL.isEmpty());
//adds students to the linked list from the front
LL.addFront(st3);
LL.addFront(st2);
LL.addFront(st1);
//adds students to the linked list from the back
LL.addTail(st1);
LL.addTail(st2);
LL.addTail(st3);
//prints linked list non-recursively
LL.printLL();
System.out.println("Linked list is empty?: " + LL.isEmpty());
}
this is my testing method ^ as you can see I am filling my list with student objects. The printLL() method shows all 6 objects are in fact in the array.
public boolean isEmpty()
{
Boolean e;
if (list==null)
return e=true;
else
return e=false;
}
This is my isEmpty() method. The parameters and data type is specified by my professor. For some reason my list always equals null even though it should contain 6 objects the second time I use the method. What am I missing?
My entire linked list class
public class LinkedListStud
{
private Node list;
public LinkedListStud()
{
list = null;
}
public void addFront(Student s)
{
Node oneNode = new Node(s);
oneNode.next=list;
list=oneNode;
}
public void addTail(Student s)
{
Node current;
Node oneNode = new Node(s);
if (list==null)
list=oneNode;
else
{
current=list;
while (current.next != null)
current=current.next;
current.next=oneNode;
}
}
public boolean isEmpty()
{
Boolean e=true;
if (list!=null)
return false;
else
return e;
}
public Student bestStudent()
{
Student bestStudent=list.data;
while (list.next!=null)
{
if (list.next.data.getGpa()>list.data.getGpa())
{
Student temp = list.data;
list.data=list.next.data;
list.next.data=temp;
}
list=list.next;
}
return bestStudent;
}
public void printLL()
{
while (list!=null)
{
System.out.println(list.data);
list=list.next;
}
}
public void printLLRec(Node list)
{
if (list!=null)
{
System.out.println(list.data);
printLLRec(list.next);
}
}
Student bestStudRec(Node list)
{
Student bestStudent = list.data;
if (list!=null)
{
if (list.next.data.getGpa()>list.data.getGpa())
{
bestStudent=list.next.data;
bestStudRec(list.next);
}
}
return bestStudent;
}
private class Node
{
public Student data;
public Node next;
public Node(Student s)
{
data=s;
next=null;
}
public String toString()
{
return "" + data;
}
}
}
Problem is here:
public void printLL()
{
while (list!=null)
{
System.out.println(list.data);
list=list.next;
}
}
You replace list variable with nested list until it becomes null. Last iteration there set your LL.list to null, then while checks it and goes out. If you modify while like:
public void printLL()
{
while (list!=null)
{
System.out.println(list.data);
if (list.next == null) break;
list=list.next;
}
}
you will get what you need, but your root LL will have replaced value from last Node.
Following on from #Vadim 's answer, if you want to print it out without changing the internal list, you can introduce a local variable.
public void printLL()
{
Node temp = list;
while (temp!=null)
{
System.out.println(temp.data);
temp=temp.next;
}
}
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
This is my class:
public class MultiSet<E> extends AbstractCollection<E>
{
private int size = 0;
private Map<E, Integer> values = new HashMap<E, Integer>();
public MultiSet()
{
}
public MultiSet(Collection<E> c)
{
addAll(c);
}
#Override
public boolean add(E o)
{
throw new UnsupportedOperationException();
}
#Override
public boolean remove(Object o)
{
throw new UnsupportedOperationException();
}
public Iterator<E> iterator()
{
return new Iterator<E>()
{
private Iterator<E> iterator = values.keySet().iterator();
private int remaining = 0;
private E current = null;
public boolean hasNext()
{
return remaining > 0 || iterator.hasNext();
}
public E next()
{
if (remaining == 0)
{
remaining = values.get(current);
}
remaining--;
return current;
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public boolean equals(Object object)
{
if (this == object) return true;
if (this == null) return false;
if (this.getClass() != object.getClass()) return false;
MultiSet<E> o = (MultiSet<E>) object;
return o.values.equals(values);
}
public int hashCode()
{
return values.hashCode()*163 + new Integer(size).hashCode()*389;
}
public String toString()
{
String res = "";
for (E e : values.keySet());
//res = ???;
return getClass().getName() + res;
}
public int size()
{
return size;
}
}
So basically, i need to implement my add/remove-methods correctly, to add or remove elements to/from the Set.
To me, it seems like my equals is correct, but Eclipse says that in the line:
MultiSet<E> o = (MultiSet<E>) object;
there is an unchecked cast from object to Multiset<E>
Any thoughts?
Also, in my toString method, i'm not 100% sure how to define "res"?
Thanks,
// Chris
use this instead:
MultiSet<?> o = (MultiSet<?>) object;
this is necessary due to how generics are implemented in java.
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.