The essential idea behind nesting loops is multiplication.
Expanding on Michael Burr's answer, if the outer for
loops are doing nothing but controlling a count, then your nested for
loops over n
counts are simply a more complicated way of iterating over the product of the counts with a single for
loop.
Now, let's extend this idea to Lists. If you're iterating over three lists in nested loops, this is simply a more complicated way of iterating over the product of the lists with a single loop. But how do you express the product of three lists?
First, we need a way of expressing the product of types. The product of two types X
and Y
can be expressed as a generic type like P2<X, Y>
. This is just a value that consists of two values, one of type X
, the other of type Y
. It looks like this:
public abstract class P2<A, B> {
public abstract A _p1();
public abstract B _p2();
}
For a product of three types, we just have P3<A, B, C>
, with the obvious third method. A product of three lists, then, is achieved by distributing the List functor over the product type. So the product of List<X>
, List<Y>
, and List<Z>
is simply List<P3<X, Y, Z>>
. You can then iterate over this list with a single loop.
The Functional Java library has a List
type that supports multiplying lists together using first-class functions and product types (P2, P3, etc. which are also included in the library).
For example:
for (String x : xs) {
for (String y : ys) {
for (String z : zs) {
doSomething(x, y, z);
}
}
}
Is equivalent to:
for (P3<String, String, String> p : xs.map(P.p3()).apply(ys).apply(zs)) {
doSomething(p._1(), p._2(), p._3());
}
Going further with Functional Java, you can make doSomething
first-class, as follows. Let's say doSomething
returns a String:
public static final F<P3<String, String, String>, String> doSomething =
new F<P3<String, String, String>, String>() {
public String f(final P3<String, String, String> p) {
return doSomething(p._1(), p._2(), p._3());
}
};
Then you can eliminate the for-loop altogether, and collect the results of all the applications of doSomething
:
List<String> s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);