Reputation: 8847
I have a class Polygon
on which I wish to implement two iterators: one to run through all elements (vertices and edges in alternating order) just ONCE, and another to run through them ad infinitum (cyclically).
From a for-each usage standpoint, my guess is that I am only going to be able to have one of the above be the default iterator that can be used with for-each, via implementation of Iterable.iterator()
. Is this correct? Or is there a way I could use for-each with both?
Upvotes: 6
Views: 6029
Reputation: 36011
An answer I think is better than those already presented is a method that turns any Iterable into a cyclic one.
public class IterableUtils {
public static class CyclicIterator<T> implements Iterator<T> {
private final Iterable<T> inner;
private Iterator<T> currentIter;
public CyclicIterator(Iterable<T> inner) {
this.inner = inner;
}
public boolean hasNext() {
if (currentIter == null || !currentIter.hasNext()) {
currentIter = inner.iterator();
}
return currentIter.hasNext();
}
public T next() {
if (currentIter == null || !currentIter.hasNext()) {
currentIter = inner.iterator();
}
return currentIter.next();
}
public void remove() {
currentIter.remove();
}
}
public static <T> Iterable<T> cycle(final Iterable<T> i) {
return new Iterable<T>() {
public Iterator<T> iterator() { return new CyclicIterator<T>(i); }
};
}
}
Then you can just implement the single iterator method in the Polygon class and use
for (Element e: polygon) {
...
}
to iterate once and
for (Element e: cycle(polygon)) { ... }
to iterate endlessly. As a bonus, the cycle modifier can be applied to any iterable.
Upvotes: 3
Reputation: 9641
Just add two methods returning two different Iterators, one for each case:
public Iterable<String> eachOnce() {
List<String> allResults = new ArrayList<String>();
// fill list
return allResults;
}
public Iterable<String> eachCyclic() {
return new Iterable<String>() {
public Iterator<String> iterator() {
return new Iterator<String>() {
public boolean hasNext() {
return true;
}
public String next() {
// TODO implement
return null;
}
public void remove() {
// do nothing
}
};
}
};
}
This is just an example with a List of Strings, just adapt.
Instead of
for (Polygon p : polygons) { }
just use
for (Polygon p : polygons.eachOnce()) { }
or the cyclic edition
Upvotes: 12