Java DeepCopy Iterator without consuming it - java

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;
}
}

Related

What Iterator.next() method do inside a for statement when used with java.util.Queue?

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.

Solution: Iterator which doesn't know if it has a next element

I wrote an iterator, which returns subgraphs of a fixed size of another given undirected simple graph.
It maintains an internal graph which is the currently calculated subgraph and has private stacks and lists from which it calculates the next subgraph.
It is not possible to know if the iterator can return another element, because maybe the algorithm terminates when trying to find the next subgraph.
In this design, the pattern of next() and hasNext() which Java offers doesn't work out. I currently wrote my own Interface BlindIterator with the following abstract methods:
/**
* #return True iff the current element is a valid return.
*/
public boolean hasCurrent();
/**
* #return Returns the current element, but does NOT generate the next element. This method can be called
* as often as wanted, without any side-effects.
*/
public T getCurrent();
/**Generates the next element, which can then be retrieved with getCurrent(). This method thus only provides
* this side-effect. If it is called while the current element is invalid, it may produce and exception,
* depending on the implementation on the iterator.
*/
public void generateNext();
Is this a common pattern and are there better designs than mine?
I believe what you have created is equivalent to the Iterator interface. Here is an implementation of Iterator using your BlindIterator:
class BlindIteratorIterator<T> implements Iterator<T> {
private BlindIterator<T> iterator;
public BlindIteratorIterator(BlindIterator<T> iterator) {
this.iterator = iterator;
iterator.generateNext();
}
#Override
public boolean hasNext() {
return iterator.hasCurrent();
}
#Override
public T next() {
T next = iterator.getCurrent();
iterator.generateNext();
return next;
}
}
You implement the iterator to preload/cache the next element (subgraph).
For example, if your elements are sourced from a Supplier, where the only method is a get() method that returns the next element, or null if no more elements are available, you would implement the Iterator like this:
public final class SupplierIterator<E> implements Iterator<E> {
private final Supplier<E> supplier;
private E next;
SupplierIterator(Supplier<E> supplier) {
this.supplier = supplier;
this.next = supplier.get(); // cache first (preload)
}
#Override
public boolean hasNext() {
return (this.next != null);
}
#Override
public E next() {
if (this.next == null)
throw new NoSuchElementException();
E elem = this.next;
this.next = supplier.get(); // cache next
return elem;
}
}
Answer by Joni has a good Iterator implementation that can use your intended BlindIterator as the source of elements.
Since you only invented the BlindIterator to work around your perceived limitations of Iterator, I'd recommend not doing that. Make the iterator implementation call the underlying "generate" logic directly.

Lazy flatMap implementation algorithm in java 10

I know java streams, and tried to implement the map, filter, fold (with custom function as argument), both the strict and lazy evaluation ways.
However i could not implement a lazy implementation of flatmap in java.
Normal map,filter, fold are just composed functions which run on the main iterator (if its list) and apply of functions is discarded if the incoming value is null.
However flatMap input function produces another list( stream) which needs to be flattened,
How is the lazy flatMap implemented in java 10? is there any document on the algorithm?
Thanks.
If you want to implement lazy flatMap, the most important part is to provide a correct implementation of Iterator. This implementation can look like this:
final class FlatMappedIterator<A, B> implements Iterator<B> {
private final Iterator<A> iterator;
private final Function<A, Iterable<B>> f;
private Iterator<B> targetIterator; // Iterator after applying `f` to element of type A
FlatMappedIterator(Iterator<A> iterator, Function<A, Iterable<B>> f) {
this.iterator = iterator;
this.f = f;
}
#Override
public boolean hasNext() {
if (targetIterator != null && targetIterator.hasNext()) {
return true;
} else if (iterator.hasNext()) {
A next = iterator.next();
Iterable<B> targetIterable = f.apply(next);
targetIterator = targetIterable.iterator();
return targetIterator.hasNext();
} else {
return false;
}
}
#Override
public B next() {
if (hasNext()) {
return targetIterator.next();
} else {
throw new NoSuchElementException();
}
}
}
So the retrieval of the next element is postponed to the moment when hasNext or next is called.
Then you need to implement the flatMap function itself. But this is easy. I'm leaving it as an exercise for the reader :)

Deduplicate Iterator

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.

Remove from a collection during iteration

I have set of connection objects (library code I cannot change) that have a send method. If the sending fails, they call back a generic onClosed listener which I implement that calls removeConnection() in my code, which will remove the connection from the collection.
The onClosed callback is generic and can be called at any time. It is called when the peer closes the connection, for example, and not just when a write fails.
However, if I have some code that loops over my connections and sends, then the onClosed callback will attempt to modify a collection during iteration.
My current code creates a copy of the connections list before each iteration over it; however, in profiling this has shown to be very expensive.
Set<Connection> connections = new ....;
public void addConnection(Connection conn) {
connections.add(conn);
conn.addClosedListener(this);
}
#Override void onClosed(Connection conn) {
connections.remove(conn);
}
void send(Message msg) {
// how to make this so that the onClosed callback can be safely invoked, and efficient?
for(Connection conn: connections)
conn.send(msg);
}
How can I efficiently cope with modifying collections during iteration?
To iterate a collection with the concurrent modification without any exceptions use List Iterator.
http://www.mkyong.com/java/how-do-loop-iterate-a-list-in-java/ - example
If you use simple for or foreach loops, you will receive ConcurrentModificationException during the element removing - be careful on that.
As an addition, you could override the List Iterator with your own one and add the needed logic. Just implement the java.util.Iterator interface.
A ConcurrentSkipListSet is probably what you want.
You could also use a CopyOnWriteArraySet. This of course will still make a copy, however, it will only do so when the set is modified. So as long as Connection objects are not added or removed regularly, this would be more efficient.
You can also use ConcurrentHashMap.
ConcurrentHashMap is thread-safe, so you don't need to make a copy in order to be able to iterate.
Take a look at this implementation.. http://www.java2s.com/Tutorial/Java/0140__Collections/Concurrentset.htm
I would write a collection wrapper that:
Keeps a set of objects that are to be removed. If the iteration across the underlying collection comes across one of these it is skipped.
On completion of iteration, takes a second pass across the list to remove all of the gathered objects.
Perhaps something like this:
class ModifiableIterator<T> implements Iterator<T> {
// My iterable.
final Iterable<T> it;
// The Iterator we are walking.
final Iterator<T> i;
// The removed objects.
Set<T> removed = new HashSet<T>();
// The next actual one to return.
T next = null;
public ModifiableIterator(Iterable<T> it) {
this.it = it;
i = it.iterator();
}
#Override
public boolean hasNext() {
while ( next == null && i.hasNext() ) {
// Pull a new one.
next = i.next();
if ( removed.contains(next)) {
// Not that one.
next = null;
}
}
if ( next == null ) {
// Finished! Close.
close();
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
// Close down - remove all removed.
public void close () {
if ( !removed.isEmpty() ) {
Iterator<T> i = it.iterator();
while ( i.hasNext() ) {
if ( removed.contains(i.next())) {
i.remove();
}
}
// Clear down.
removed.clear();
}
}
#Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
public void remove(T t) {
removed.add(t);
}
}
public void test() {
List<String> test = new ArrayList(Arrays.asList("A","B","C","D","E"));
ModifiableIterator i = new ModifiableIterator(test);
i.remove("A");
i.remove("E");
System.out.println(test);
while ( i.hasNext() ) {
System.out.println(i.next());
}
System.out.println(test);
}
You may need to consider whether your list could contain null values, in which case you will need to tweak it somewhat.
Please remember to close the iterator if you abandon the iteration before it completes.

Categories

Resources