Is there a Java idiom for pairwise iteration through the elements of a sorted Collection
? By that I mean that each iteration has access to one element of the co
For Set
s (and other non-indexable collections) you will need to use their Iterators as returned by the iterator() method of Collection
:
Iterator<Thing> iter = set.iterator();
Thing thing1 = iter.next(); // might want to check if this exists
while (iter.hasNext()) {
Thing thing2 = iter.next();
operateOnAdjacentPair(thing1, thing2);
thing1 = thing2;
}
You can do the same for Map
s, using the Iterator
of their entrySet()s.
Now that I understand your question better, you could also try this:
Iterator<Thing> iter1 = set.iterator(), iter2 = set.iterator();
if (iter2.hasNext())
iter2.next(); // burn first element
while (iter2.hasNext()) {
final Thing thing1 = iter1.next();
final Thing thing2 = iter2.next();
operateOnAdjacentPair(thing1, thing2);
}
Write an implementation of Iterator, e.g. (just writing off the top of my head, so code may not work as is)
public class PairwiseIterator<T> implements Iterator<List<T>> {
private final Iterator<T> elements;
private T last;
public PairwiseIterator(Collection<T> elements) {
this.elements = elements.iterator();
last = elements.hasNext() ? elements.next() : null;
}
@Override
public boolean hasNext() {
return elements.hasNext();
}
@Override
public List<T> next() {
List<T> result = ImmutableList.of(last, elements.next());
last = result.get(1);
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Remove not allowed with this iterator");
}
public static <U> Iterable<List<U>> iterable(final Collection<U> elements) {
return new Iterable() {
public Iterator<U> iterator() {
return new PairwiseIterator(elements);
}
}
}
}
I probably don't have the types exactly right, but the 'iterable' method makes it easy to use in foreach constructs:
for(List<String> pair : PairwiseIterator.iterable(orderedSetOfStrings)) {
// ... do what you need to ...
}
You can simply implement it the following way (and apply similar strategy towards other collections):
Iterator<Thing> iter = set.iterator();
Thing previous = iter.hasNext() ? iter.next() : null;
while (iter.hasNext()) {
final Thing current = iter.next();
operateOnAdjacentPair(previous, current);
previous = current;
}
Guava offers a PeekingIterator which can be used for this:
PeekingIterator<Thing> iter =
Iterators.peekingIterator(set.iterator());
while (iter.hasNext()) {
final Thing thing1 = iter.next();
if (iter.hasNext()) { // don't forget this one
operateOnAdjacentPair(thing1, iter.peek());
}
}
When the loop code becomes more complex, the benefit becomes more evident, maybe.
Iterator<Thing> thingerator = coll.iterator();
if (thingerator.hasNext()) {
Thing thing1 = thingerator.next();
while (thingerator.hasNext()) {
final Thing thing2 = thingerator.next();
doStuffToThings(thing1, thing2);
thing1 = thing2;
}
}