What\'s the best way to iterate over a list while processing 2 elements at the same time?
Example:
List strings = Arrays.asList(\"item
Now in Java 8, by using https://github.com/wapatesh/fig
You can write:
seq.forEachSlice(2, (values)->{
// [1,2] [3, 4]
});
You can avoid indexing with an Iterator; this works for any Iterable, not just a list. Just get an iterator and increment it twice per loop iteration:
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
Iterator<String> stringsIterator = strings.iterator();
while (stringsIterator.hasNext()) {
String first = stringsIterator.next();
String second = stringsIterator.next();
System.out.println("First [" + first + "] - Second [" + second + "]");
}
This assumes a list of even length, and throws NoSuchElementException
on the last pass if it's odd length. You can handle this in various ways:
try
-catch
;Checking the second element:
List<String> strings = Arrays.asList("item 1", "item 2", "item 3");
Iterator<String> stringsIterator = strings.iterator();
while (stringsIterator.hasNext()) {
String first = stringsIterator.next();
String second = stringIterator.hasNext() ? stringIterator.next() : null;
System.out.println("First [" + first + "] - Second [" + second + "]");
}
Iterators confuse some people, so you can also use a for-each loop with a branch and an auxiliary flip-flop variable for parity. This is much worse, since it makes the loop's logic much more complicated to simplify the iteration: rather than the action being done once per pass through the loop, in sequence and without branching, you instead have to go through it twice and branch mentally. Note that this skips the last element if it's of odd length; could add a check of isFirst
afterwards if want to handle these cases too.
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
boolean isFirst = true;
String first = null;
String second = null;
for (String string : strings) {
if (isFirst) {
first = string;
isFirst = false;
} else {
second = string;
isFirst = true;
System.out.println("First [" + first + "] - Second [" + second + "]");
}
}
Lastly, note that all these iterators and auxiliary variables have excess scope (they are only of use for the loop itself, so they pollute the local environment): they could be wrapped in blocks to limit the scope, though usually the resulting nesting is considered worse than the excess scope:
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
{
Iterator<String> stringsIterator = strings.iterator();
while (stringsIterator.hasNext()) {
String first = stringsIterator.next();
String second = stringsIterator.next();
System.out.println("First [" + first + "] - Second [" + second + "]");
}
}
We should of course provide a solution for the general case ;-)
public static void main(String[] args) {
List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
for (Pair<Integer> p : Pair.over(list)) {
System.out.printf("%d, %d\n", p.first, p.second);
}
}
static class Pair<T> {
T first;
T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public static <T> Iterable<Pair<T>> over(Collection<T> collection) {
return new PairWise<T>(collection);
}
private static class PairWise<T> implements Iterable<Pair<T>>, Iterator<Pair<T>> {
final Iterator<T> iterator;
PairWise(Collection<T> collection) {
super();
this.iterator = collection.iterator();
}
@Override
public Iterator<Pair<T>> iterator() {
return this;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Pair<T> next() {
T first = null;
T second = null;
if (iterator.hasNext())
first = iterator.next();
else
throw new NoSuchElementException();
if (iterator.hasNext())
second = iterator.next();
return new Pair<T>(first, second);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
What if you increase i by 2 in each iteration? Should do... Otherwise consider increase i inside the actual loop
List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
int i = 0;
for(; i < strings.size() - 1; i+=2){
String first = strings.get(i);
String second = strings.get(i + 1);
System.out.println("First [" + first + "] - Second [" + second + "]");
}
//For odd sized lists
if(i < strings.size()){
System.out.println("First [" + strings.get(i) + "]");
}