views:

1105

answers:

6

In other words, can I do something like

for() {
    for {
       for {
       }
    }
}

Except N times? In other words, when the method creating the loops is called, it is given some parameter N, and the method would then create N of these loops nested one in another?

Of course, the idea is that there should be an "easy" or "the usual" way of doing it. I already have an idea for a very complicated one.

+12  A: 

It sounds like you may want to look into recursion.

jjnguy
Got me by 1 second.
Michael Haren
... and learn the meaning of the term "Stack Overflow"! :)
sjbotha
Maybe quicksort could be a good example
Herrmann
This still does not answer the question. For-iteration IS a kind of recursion. Perhaps you intend to include an example of *mutual* recursion?
Apocalisp
Man..I can't think of a good, compact, example
jjnguy
+3  A: 

Problem needs more specification. Maybe recursion will help you, but keep in mind that recursion is almost always an alternative to iteration, and vice versa. It may be that a 2-level nested loop can be sufficient for your needs. Just let us know what problem you're trying to solve.

John Zwinck
+6  A: 

You might want to explain what you really want to do.

If the outer for loops are doing nothing but controlling a count, then your nested for loops are simply a more complicated way of iterating by a count that could be handled by a single for loop.

For example:

for (x = 0; x < 10; ++x) {
  for (y = 0; y < 5; ++y) {
    for (z = 0; z < 20; ++z) {
      DoSomething();
    }
  }
}

Is equivalent to:

for (x = 0; x < 10*5*20; ++x) {
  DoSomething();
}
Michael Burr
Good answer. This captures the essence of nesting loops. See my answer for a generalization of this idea.
Apocalisp
+3  A: 

I was actually thinking about this the other day.

An example that is probably not perfect but pretty close to what I think is being asked would be printing out a directory tree

public void printTree(directory) {
   for(files in directory) {
      print(file);
      if(file is directory) {
          printTree(file);
      }
   }
}

this way you end up with a stack of for loops nested inside each other, without the hassle of figuring out exactly how they should go together.

Wayne
Apparently you are supposed to do something not what I did to add code..
Wayne
@Wayne: I fixed the formatting, just indent your code by four spaces.
Greg Hewgill
Your printTree function doesn't print anything..
dancavallaro
use your imagination...
Wayne
This is a typical use for recursion, where you are traversing a recursive datastructure.
Rolf Rander
+9  A: 

jjnguy is right; recursion lets you dynamically create variable-depth nesting. However, you don't get access to data from the outer layers without a little more work. The "in-line-nested" case:

for (int i = lo; i < hi; ++i) {
    for (int j = lo; j < hi; ++j) {
        for (int k = lo; k < hi; ++k) {
            // do something **using i, j, and k**
        }
    }
}

keeps the variables i, j, and k in scope for the innermost body to use.

Here's one quick hack to do that:

public class NestedFor {

    public static interface IAction {
        public void act(int[] indices);
    }

    private final int lo;
    private final int hi;
    private final IAction action;

    public NestedFor(int lo, int hi, IAction action) {
        this.lo = lo;
        this.hi = hi;
        this.action = action;
    }

    public void nFor (int depth) {
        n_for (0, new int[0], depth);
    }

    private void n_for (int level, int[] indices, int maxLevel) {
        if (level == maxLevel) {
            action.act(indices);
        } else {
            int newLevel = level + 1;
            int[] newIndices = new int[newLevel];
            System.arraycopy(indices, 0, newIndices, 0, level);
            newIndices[level] = lo;
            while (newIndices[level] < hi) {
                n_for(newLevel, newIndices, maxLevel);
                ++newIndices[level];
            }
        }
    }
}

The IAction interface stipulates the role of a controlled action which takes an array of indices as the argument to its act method.

In this example, each instance of NestedFor is configured by the constructor with the iteration limits and the action to be performed by the innermost level. The parameter of the nFor method specifies how deeply to nest.

Here's a sample usage:

public static void main(String[] args) {
    for (int i = 0; i < 4; ++i) {
        final int depth = i;
        System.out.println("Depth " + depth);
        IAction testAction = new IAction() {
            public void act(int[] indices) {
                System.out.print("Hello from level " + depth + ":");
                for (int i : indices) { System.out.print(" " + i); }
                System.out.println();
            }
        };
        NestedFor nf = new NestedFor(0, 3, testAction);
        nf.nFor(depth);
    }
}

and the (partial) output from its execution:

Depth 0
Hello from level 0:
Depth 1
Hello from level 1: 0
Hello from level 1: 1
Hello from level 1: 2
Depth 2
Hello from level 2: 0 0
Hello from level 2: 0 1
Hello from level 2: 0 2
Hello from level 2: 1 0
Hello from level 2: 1 1
Hello from level 2: 1 2
Hello from level 2: 2 0
Hello from level 2: 2 1
Hello from level 2: 2 2
Depth 3
Hello from level 3: 0 0 0
Hello from level 3: 0 0 1
Hello from level 3: 0 0 2
Hello from level 3: 0 1 0
...
Hello from level 3: 2 1 2
Hello from level 3: 2 2 0
Hello from level 3: 2 2 1
Hello from level 3: 2 2 2
joel.neely
This should be the correct answer!
Skip Head
A: 

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);
Apocalisp