This is not usually the case, but sometimes it's nice to avoid nested iterators. If a block of code has too many, they can become visually disruptive. For an example, take a look at line 52 of this Sudoku example.
In these cases I find Python's product generator particularly useful. Consider the output of the following code:
from itertools import product
for i, j, k in product(range(2), range(10,12), range(20,22)):
print(i, j, k)
# Output:
# 0 10 20
# 0 10 21
# 0 11 20
# 0 11 21
# 1 10 20
# 1 10 21
# 1 11 20
# 1 11 21
This behaves just like three nested for loops. You can give it an arbitrary number of sequences, too. Scala has a similar construct built into its for loops which is quite nice. Just separate your iterables by semicolons:
for ( a <- 0 to 1; b <- 10 to 11; c <- 20 to 21 ) println(a + " " + b + " " + c) // 0 10 20 // ...
The real power here lies in the ability to apply filters to your iterables. Here we only execute the nested loops if a is even:
for ( a <- 0 to 9 if a % 2 == 0; b <- 10 to 11; c <- 20 to 21 ) println(a + " " + b + " " + c) // 0 10 20 // 0 10 21 // 0 11 20 // 0 11 21 // 2 10 20 // 2 10 21 // 2 11 20 // 2 11 21 // 4 10 20 // ...
Of course, the more expressive a syntactic construct, the more ripe it is for abuse. It's not as blindingly obvious what the differences between the above and the following are as it would be with nesting, especially since they have the same output:
for ( a <- 0 to 9; b <- 10 to 11; c <- 20 to 21 if a % 2 == 0 ) println(a + " " + b + " " + c) // 0 10 20 // ...
To see this a bit more clearly, we can add tests against println(...) to the innermost loop. For the uninitiated, println(...) returns Unit (think None or null), which is the same as (). The println(...) calls are essentially side effects:
for (
a <- 0 to 9 if a % 2 == 0;
b <- 10 to 11;
c <- 20 to 21 if println("iterating") == ()
) println(a + " " + b + " " + c)
// iterating
// 0 10 20
// iterating
// 0 10 21
// iterating
// 0 11 20
// iterating
// 0 11 21
// iterating
// 2 10 20
// ...
We can chain our conditions nicely. Of course we have the put the println(...) first so it always executes. Note the extra iterations before a takes the value 2:
for (
a <- 0 to 9;
b <- 10 to 11;
c <- 20 to 21 if println("iterating") == () if a % 2 == 0
) println(a + " " + b + " " + c)
// iterating
// 0 10 20
// iterating
// 0 10 21
// iterating
// 0 11 20
// iterating
// 0 11 21
// iterating
// iterating
// iterating
// iterating
// iterating
// 2 10 20
// ...