Implement an iterator(Generic) which skips next element if it is equal to last printed element.
e.g : AAABBCCCCD
On complete iteration will print ABCD.
Below is my attempt. Please suggest if it can be done in a better way.
import java.util.Iterator;
public class DeDupIterator<E> implements Iterator<E> {
E next = null;
Iterator<E> itr;
public DeDupIterator(Iterator<E> iter) {
itr = iter;
next = itr.next();
}
#Override
public boolean hasNext() {
if(itr.hasNext())
if (next != null) {
return true;
}
return false;
}
#Override
public E next() {
E item=null;
while (itr.hasNext()) {
item = (E) itr.next();
if (!item.equals(next)) {
E temp = next;
next = item;
return temp;
}
}
next = item;
return next;
}
#Override
public void remove() {
itr.remove();
}
}
It's hard to answer this question without actually writing the code for you.
I'll just focus on main issues with this code:
it doesn't work for empty collections, because it calls itr.next() unconditionally in the constructor, which leads to an exception
it doesn't work for a single element collections, because hasNext() returns false instead of true - this is because you call itr.next() in the constructor and then in hasNext() you first check itr.hasNext()
remove() is completely wrong, because itr.next() was called earlier
it should throw NoSuchElementException in next() if there is no element to return, but it doesn't
How to fix it?
I would start by removing itr.next() from constructor as it's messing many things up.
Then you have to somehow distinguish between two cases: when itr.next() was called in advance or not. E.g. add a boolean field to facilitate that.
You will have to call itr.next() in advance if hasNext() is called.
Also you should be prepared that itr.next() returns null as a completely valid value that can be stored in a collection. You should not rely on next to be not null. For this reason you should have one more boolean that determines whether your next field actually holds a value or is empty.
The remove() method should probably remove all the duplicates and not only one element. If you find it too demanding to implement you can always throw UnsupportedOperationException. If you decide to implement it, remember to throw IllegalStateException if next() has not yet been called, or remove() has already been called after the last next() call
This should be enough for you to get the right solution yourself. Good luck.
Related
For example:
public class Test {
public static void main(String[] args) {
Queue<String> names = new LinkedList<>(Arrays.asList("First", "Middle", "Last"));
System.out.println("Queue before the loop: " + names);
System.out.println("Printing loop...");
for (Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
System.out.println(name);
}
System.out.println("Queue after the loop: " + names);
}
}
Output:
Queue before the loop: [First, Middle, Last]
Printing loop...
First
Middle
Last
Queue after the loop: [First, Middle, Last]
I know how the next() method traverse the LinkedList. But when it is called on a Queue.iterator() like, i.next() what does it do? As you can see from the output it haven't removed any element from the queue. which I thought would be the case, since Queue only have remove()/poll().
Iterator is simply used to iterate over a Collection. In this case, you could have used a for-each for the same result:
for(String name : names){
System.out.println(name);
}
Based on your question however, I assume you want to iterate over the Queue, popping and printing each item in FIFO order (hence the use of your LinkedList). In that case, you may simply want to loop names.size() amount of times, and calling .remove() to pop an item each iteration, like this:
for(int n = names.size(); n > 0; n--){
String name = names.remove();
System.out.println(name);
}
Output:
Queue before the loop: [First, Middle, Last]
Printing loop...
First
Middle
Last
Queue after the loop: []
Try it online.
EDIT: To explain a bit more of what's going on for the .iterator():
If we look at the source code of the Iterator, we can see it's an interface. Each Collection-implementation will have its own individual Iterator implementation.
Looking at the source code of the Queue, the iterator() method is this:
/**
* Returns an iterator that iterates over the items in this queue in FIFO order.
*
* #return an iterator that iterates over the items in this queue in FIFO order
*/
public Iterator<Item> iterator() {
return new ListIterator();
}
// an iterator, doesn't implement remove() since it's optional
private class ListIterator implements Iterator<Item> {
private Node current = first; // node containing current item
public boolean hasNext() {
return current != null;
}
public void remove() {
throw new UnsupportedOperationException();
}
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
As you can see, it stores the Node first of Queue as its current when the ListIterator is created in the iterator() method.
In the actual next()-method, it uses neither the remove() nor poll() methods of the Queue (nor get()..), so the items aren't actually popped. Instead, it simply stores the current Node temporarily with Item item = current.item; then updates the current Node to the next one with current = current.next; after which it will return that temporary item.
Since names is a LinkedList object and LinkedList does't have
any iterator() method in it, names.iterator() would call
that method in
AbstractSequentialList
(immediate super class of LinkedList).
However, by tracking the call stack (can be done easily through a GUI debugger of any decent java IDE) when initializing i = names.iterator() one can easily see it calls the method listIterator(0) method here. Eventhough AbstractList has it's own implementation of listIterator(int index), LinkedList has overriden that same method ;
Segment of LinkedList.java :
package java.util;
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
*
* (code contraction...)
*
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
Hence, obviously names.iterator() would return an object through return new ListItr(index), which is an inner class of LinkedList.
Now we can clearly see when calling i.next(), it actually calls the next() method in the inner class ListItr. Also it uses the class variable;
private Node<E> next;
to track, to where the iterator is pointing next.
This comes into play when considering the performance of the enhanced for loop.
Segment of Oracle docs for enhance-for-loops :
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableModifiersopt TargetType Identifier = (TargetType) #i.next();
Statement
}
As you can see this uses the #i.next() method and since names(in the original question's example) is a variable of type Queue, one can in-the-dark assume #i.next() in the enhanced-for-loop uses this implementation which is in AbstractList and it questionably uses some get(int index) method, hence poor performance (a poor,unfortunate guy like me, did the same deduction and caught up in a hay-stack of code. LOL).
On that false deduction I asked this question in this forum and after digging deeper for several days, now I can see there are no any performance reduction(not that I know of) when using an enhanced-for-loop to iterate over a LinkedList object due to the fact,
that iterator object(#i) uses a variable Node<E> next to keep the reference to the next object in-order to use in the enhanced-for-loop 's next iteration.
How can I copy my iterator to another one without consuming it ? Or at least if I can reset the index back to first element after I can consume it.
I am looking for something like below, where it should still print the values after copying it;
Iterator iter2=copy(iter1);
while(iter1.hasNext())
{
System.out.println(iter1.next()); // Should print this, even after copy
}
The contract of an Iterator is to be an "only forward" way of iterating through a series of objects.
As mentioned in your comment, you are trying to log the values of an Iterator, yet still the use the Iterator elsewhere.
You could though do something tricky by wrapping the Iterator with a custom class which calls the wrapped Iterator and logs the values as the next method is called.
A bit hacky. Not recommended in general but could be useful in a debugging situation.
You would construct this WrappedIterator using the original Iterator as parameter and then pass the WrappedIterator to the code which consumes it.
public class WrappedIterator<T> implements Iterator<T> {
private Iterator<T> iterator;
public WrappedIterator(Iterator<T> iterator) {
this.iterator = iterator;
}
#Override
public void remove() {
this.iterator.remove();
}
#Override
public boolean hasNext() {
return this.iterator.hasNext();
}
#Override
public T next() {
T next = iterator.next();
System.out.println(next);
return next;
}
}
For school I had to made a kind of linked list like queue.
My nodes have 3 attributes:
Node left (Node left of the node)
Node right (Node right of the node)
Object item (The object that is stored in the list)
I also have to make the list iterable so implemented that interface.
The problem I have now is that if there are for example 4 items in the list, it only shows 3 of them.
So if for example the list has 4 strings in it, 'a', 'b', 'c' and 'd' the output is:
b
c
d
My hasNext method looks like:
#Override
public boolean hasNext() {
return node.getRight() != null;
}
and my next method looks like:
#Override
public T next() {
node = node.getRight();
Object item = node.getItem();
return (T)item;
}
If I return the item of the node instead of the node on the right I get
a
b
c
as return but that is also not good because it skips the last one. And when you read the API next should return the next value so I guess my next method has to be as it is.
The iterator's methods should be implemented as this:
#Override
public T next() {
Object item = node.getItem();
node = node.getRight();
return (T)item;
}
#Override
public boolean hasNext() {
return node != null;
}
Just think about other iterators. At the first call of next() they return the first element and THEN they move forward to the second. When you are pointing to the last element, next() should return it and move forward (i.e. point to null). To be able to do this, the test inside of hasNext should be on the current item, not on the next, otherwise you could not get the last element.
You probably initialize the node property by setting it to the first node, so a next () call points to the second. Try checking for the first node:
boolean first = true;
#Override public T next() {
if (!first) {
node = node.getRight();
}
else
first = false;
Object item = node.getItem();
return (T)item;
}
taking a java class and we have to design our own HashSet class. (not using the JAVA apis)
I have to implement and iterator for this, and I am confused about the semantics of using one.
Not sure if a call should be allowed to be made to Next() which will move the index of the iterator, or if a user must absolutely use next() in conjunction with a hasNext() loop which will move the index.
For instance, what would happen if the user had several consecutives calls to next() without hasNext() ?
Thanks for everyone's help!
public class HashWordSet implements WordSet {
private int size;
private Node[] buckets = new Node[8];
//above is only provided for mention of variables
private class Node {
Word value;
Node next = null;
public Node(Word word) {value = word;}
public String toString() {return value.toString();}
}
class WordIterator implements Iterator<Word> {
private Node next;
private int index = 0;
public Word next() {
Node element = next;
if (element == null)
throw new NoSuchElementException();
if ((next = element.next) == null) {
Node[] temp = buckets;
while (index < temp.length && (next = temp[index++]) == null)
;
}
return element.value;
}
public boolean hasNext() {
return (next != null);
}
The Javadoc specifies that if next is called and there isn't a next element, you must throw a NoSuchElementException. That said, you should not assume that hasNext is always called before next -- or that hasNext is called only once!
The typical way to do this for a hash table is that
hasNext advances through the hash table if it's not already pointing to a valid element.
next calls hasNext as its first step, and after it's done returning the next element, increments to the next position in the hash table (without checking to see if there is an element in that position).
Just follow the API as shown here http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Iterator.html
If a user calls next() and there are no more elements, you throw a NoSuchElementException.
You absolutely should be able to use an iterator by only calling next(), assuming that it's in a valid state for you to do that. Checking hasNext() on each iteration is the idiomatic way to do things, but it is not required and you should not rely on callers doing this.
In fact, hasNext() should be idempotent and essentially should not change any state of your iterator at all. Since it doesn't change the state, by definition it can't make a different whether it was previously called or not.
So basically yes - every time next() is called, you should return the "current" element of your iterator, and then advance the "pointer" (for whatever those concepts mean in your implementation).
What would happen if the user had several consecutives calls to next() without hasNext()?
If there were sufficient elements left to iterate over, he would get successive elements returned with each call to next(). If he thinks he knows better, and calls next() after reaching the end of the iterator (i.e. when hasNext() would have returned false), then as per the Javadocs you should throw a NoSuchElementException.
public ReversibleIterator iterator();
can anyone help me make this method? ill put up what i have done so far
The ReversibleIterator should behave as follows. The first call to next or previous should return the first or last element of the list, respectively. Subsequent calls to next/previous should return the element that is next/previous with respect to the antecedent call to next/previous. For example, if two calls to next result in Sunday and Monday, then a following call to previous should return Sunday.
public ReversibleIterator<T> iterator() {
PublicLinkedList<T> list = new PublicLinkedList<T>();
PublicNode<T> node = list.head;
while (node.getElement() != null) {
list.add(node.getElement());
node = node.getNext();
}
ReversibleIterator<T> rIter = new ReversibleIterator<T>(list);
return rIter;
}
Java's ListIterator is what you need. The big advantage: It already exists.
You can retrieve it from any list in Java by calling the listIterator() function.