有没有办法在Java中执行n级嵌套循环?

有没有办法在Java中执行n级嵌套循环?,java,recursion,loops,for-loop,Java,Recursion,Loops,For Loop,换言之,我能做些类似的事情吗 for() { for { for { } } } 除了N次?换句话说,当调用创建循环的方法时,给它一些参数N,然后该方法将创建嵌套在另一个循环中的N个循环 当然,我们的想法是应该有一种“简单”或“通常”的方式来做。对于一个非常复杂的问题,我已经有了一个想法。听起来您可能想研究这个问题,需要更多的说明。也许递归会对您有所帮助,但请记住,递归几乎总是迭代的替代方法,反之亦然。可能两级嵌套循环就足以满足您的需要。请告诉我们您

换言之,我能做些类似的事情吗

for() {
    for {
       for {
       }
    }
}
除了N次?换句话说,当调用创建循环的方法时,给它一些参数N,然后该方法将创建嵌套在另一个循环中的N个循环


当然,我们的想法是应该有一种“简单”或“通常”的方式来做。对于一个非常复杂的问题,我已经有了一个想法。

听起来您可能想研究这个问题,需要更多的说明。也许递归会对您有所帮助,但请记住,递归几乎总是迭代的替代方法,反之亦然。可能两级嵌套循环就足以满足您的需要。请告诉我们您要解决的问题。

您可能需要解释您真正想要做的事情

如果外部
for
循环除了控制计数外什么都不做,那么嵌套的
for
循环只是一种更复杂的计数迭代方式,可以由单个
for
循环处理

例如:

for (x = 0; x < 10; ++x) {
  for (y = 0; y < 5; ++y) {
    for (z = 0; z < 20; ++z) {
      DoSomething();
    }
  }
}
for (String x : xs) {
   for (String y : ys) {
     for (String z : zs) {
       doSomething(x, y, z);
     }
   }
}
(x=0;x<10;++x)的
{
对于(y=0;y<5;++y){
对于(z=0;z<20;++z){
DoSomething();
}
}
}
相当于:

for (x = 0; x < 10*5*20; ++x) {
  DoSomething();
}
for (P3<String, String, String> p : xs.map(P.p3()).apply(ys).apply(zs)) {
   doSomething(p._1(), p._2(), p._3());
}
(x=0;x<10*5*20;++x)的
{
DoSomething();
}

前几天我真的在想这个问题

一个可能并不完美但非常接近我所想的问题的例子是打印出一个目录树

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

这样,您就可以得到嵌套在彼此内部的一堆for循环,而不必费心弄清楚它们应该如何组合;递归允许动态创建可变深度嵌套。但是,如果不多做一点工作,就无法从外层访问数据。“内嵌嵌套”情况:

IAction
接口规定了受控操作的角色,该操作将一系列索引作为其
act
方法的参数

在本例中,
NestedFor
的每个实例由构造函数配置,其中包含迭代限制和最内层执行的操作。方法的参数指定嵌套的深度

下面是一个示例用法:

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

嵌套循环背后的基本思想是乘法

扩展Michael Burr的答案,如果外部
for
循环除了控制计数外什么都不做,那么嵌套的
for
循环在
n
计数上只是一种更复杂的方法,用单个
for
循环迭代计数的乘积

现在,让我们将这个想法扩展到列表。如果您在嵌套循环中迭代三个列表,那么这只是用一个循环迭代列表乘积的一种更复杂的方法。但是如何表示三个列表的乘积呢

首先,我们需要一种表示类型乘积的方法。两种类型的乘积
X
Y
可以表示为类属类型,如
P2
。这只是一个由两个值组成的值,一个为
X
,另一个为
Y
。看起来是这样的:

public abstract class P2<A, B> {
  public abstract A _p1();
  public abstract B _p2();
}
相当于:

for (x = 0; x < 10*5*20; ++x) {
  DoSomething();
}
for (P3<String, String, String> p : xs.map(P.p3()).apply(ys).apply(zs)) {
   doSomething(p._1(), p._2(), p._3());
}
然后您可以完全消除for循环,并收集
doSomething
的所有应用程序的结果:

List<String> s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);
List s=xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);
字符串(int n){
StringBuilder bldr=新的StringBuilder();
对于(int i=0;i=0;i--){
对于(int j=0;j
为循环骨架创建良好的嵌套结构;-) 不太严重,我知道递归解决方案会更优雅。

public void recursiveFor(Deque index,int[]ranges,int n){
public void recursiveFor(Deque<Integer> indices, int[] ranges, int n) {

    if (n != 0) {

       for (int i = 0; i < ranges[n-1]; i++) {

          indices.push(i);
          recursiveFor(indices, ranges, n-1);
          indices.pop();
       }
    }

    else {

       // inner most loop body, access to the index values thru indices
       System.out.println(indices);
    }
}
如果(n!=0){ 对于(int i=0;i<范围[n-1];i++){ 指数.推动(i); 递归(指数,范围,n-1); index.pop(); } } 否则{ //最内部的循环体,通过索引访问索引值 系统输出打印项次(索引); } }
电话示例:

int[] ranges = {2, 2, 2};

recursiveFor(new ArrayDeque<Integer>(), ranges, ranges.length);
int[]范围={2,2,2};
recursiveFor(新ArrayQue(),ranges,ranges.length);

为了简洁起见,我将代码放在这里:

void variDepth(int depth, int n, int i) {
    cout<<"\n d = "<<depth<<" i = "<<i;
    if(!--depth) return;
    for(int i = 0;i<n;++i){
        variDepth(depth,n,i);
    }
}
void testVariDeapth()
{   variDeapth(3, 2,0);
}

2015年编辑:与上一个咒语一样,我制作了以下程序包来处理这个问题

用法如下

public static void main(String... args) {
    NFor<Integer> nfor = NFor.of(Integer.class)
            .from(0, 0, 0)
            .by(1, 1, 1)
            .to(2, 2, 3);

    for (Integer[] indices : nfor) {
        System.out.println(java.util.Arrays.toString(indices));
    }
}
它还支持除
小于
以外的条件。使用方法(使用
import static.*;
):

显然,支持不同长度和不同类的循环(所有装箱的数值原语)。默认值(如果未指定)是从(0,…)。由(1,…);但必须指定一个到(…)

NForTest
文件应演示几种不同的使用方法


这种方法的基本前提是,只需每轮推进“索引”,而不是使用递归

// i[0] = 0..1  i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() { 
    void act(int[] i) { 
        System.err.printf("%d %d %d\n", i[0], i[1], i[2] );
    }
}
或者在Java 8中:

// i[0] = 0..1  i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, 
   i -> { System.err.printf("%d %d %d\n", i[0], i[1], i[2]; } 
);
支持这一点的实现是:

/**
 * Uses recursion to perform for-like loop.
 *  
 * Usage is 
 *  
 *    MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() { 
 *        void act(int[] indices) { 
 *            System.err.printf("%d %d %d\n", indices[0], indices[1], indices[2] );
 *        }
 *    }
 *  
 * It only does 0 - (n-1) in each direction, no step or start 
 * options, though they could be added relatively trivially.
 */
public class MultiForLoop {

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

    static void loop(int[] ns, Callback cb) {
        int[] cur = new int[ns.length];
        loop(ns, cb, 0, cur);
    }

    private static void loop(int[] ns, Callback cb, int depth, int[] cur) {
        if(depth==ns.length) {
            cb.act(cur);
            return;
        }

        for(int j = 0; j<ns[depth] ; ++j ) {
            cur[depth]=j;
            loop(ns,cb, depth+1, cur);
        }
    }
}
/**
*使用递归执行类似的循环。
*  
*用法是
*  
*循环(新的int[]{2,4,5},新的MultiForLoop.Callback(){
*无效行为(int[]索引){
*System.err.printf(“%d%d%d\n”,索引[0],索引[1],索引[2]);
*        }
*    }
*  
*它在每个方向上只执行0-(n-1),没有步进或启动
*选项,尽管它们可以相对简单地添加。
*/
公共类多重循环{
公共静态接口回调{
无效法案(int[]指数);
}
静态无效循环(int[]ns,回调cb){
int[]cur=新的int[ns.l]
public static void main(String... args) {
    NFor<Integer> nfor = NFor.of(Integer.class)
            .from(0, 0, 0)
            .by(1, 1, 1)
            .to(2, 2, 3);

    for (Integer[] indices : nfor) {
        System.out.println(java.util.Arrays.toString(indices));
    }
}
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
NFor<Integer> nfor = NFor.of(Integer.class)
        .from(-1, 3, 2)
        .by(1, -2, -1)
        .to(lessThanOrEqualTo(1), greaterThanOrEqualTo(-1), notEqualTo(0));
[-1, 3, 2]
[-1, 3, 1]
[-1, 1, 2]
[-1, 1, 1]
[-1, -1, 2]
[-1, -1, 1]
[0, 3, 2]
[0, 3, 1]
[0, 1, 2]
[0, 1, 1]
[0, -1, 2]
[0, -1, 1]
[1, 3, 2]
[1, 3, 1]
[1, 1, 2]
[1, 1, 1]
[1, -1, 2]
[1, -1, 1]
// i[0] = 0..1  i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() { 
    void act(int[] i) { 
        System.err.printf("%d %d %d\n", i[0], i[1], i[2] );
    }
}
// i[0] = 0..1  i[1]=0..3, i[2]=0..4
MultiForLoop.loop( new int[]{2,4,5}, 
   i -> { System.err.printf("%d %d %d\n", i[0], i[1], i[2]; } 
);
/**
 * Uses recursion to perform for-like loop.
 *  
 * Usage is 
 *  
 *    MultiForLoop.loop( new int[]{2,4,5}, new MultiForLoop.Callback() { 
 *        void act(int[] indices) { 
 *            System.err.printf("%d %d %d\n", indices[0], indices[1], indices[2] );
 *        }
 *    }
 *  
 * It only does 0 - (n-1) in each direction, no step or start 
 * options, though they could be added relatively trivially.
 */
public class MultiForLoop {

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

    static void loop(int[] ns, Callback cb) {
        int[] cur = new int[ns.length];
        loop(ns, cb, 0, cur);
    }

    private static void loop(int[] ns, Callback cb, int depth, int[] cur) {
        if(depth==ns.length) {
            cb.act(cur);
            return;
        }

        for(int j = 0; j<ns[depth] ; ++j ) {
            cur[depth]=j;
            loop(ns,cb, depth+1, cur);
        }
    }
}
for(i0=0;i0<10;i0++)
    for(i1=0;i1<10;i1++)
        for(i2=0;i2<10;i2++)
            ....
                for(id=0;id<10;id++)
                    printf("%d%d%d...%d\n",i0,i1,i2,...id);
void nestedToRecursion(counters,level){
    if(level == d)
        computeOperation(counters,level);
    else
    {
        for (counters[level]=0;counters[level]<10;counters[level]++)
            nestedToRecursion(counters,level+1);
    }
}
void computeOperation(counters,level){
    for (i=0;i<level;i++)
        printf("%d",counters[i]);
    printf("\n");
}
nestedToRecursion(counters,0);
for (x = 0; x < base; ++x) {
  for (y = 0; y < loop; ++y) {
      DoSomething();
  }
}
for (x = 0; x < base*loop; ++x){
    DoSomething();
}
char[] numbs = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
     public void printer(int base, int loop){
       for (int i = 0; i < pow(base, loop); i++){
         int remain = i;
         for (int j = loop-1; j >= 0; j--){
           int digit = remain/int(pow(base, j));
           print(numbs[digit]);
           remain -= digit*pow(base, j);
         }
         println();
       }
     }
00
01
02
03
04
...
97
98
99
public boolean isValidAlternativeSelection (int[] alternativesSelected) {
    boolean allOK = true;
    int nPaths= myAlternativePaths.size();
    for (int i=0; i<nPaths; i++) {
        allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
    }
    return allOK;
}


public boolean getNextValidAlternativeSelection (int[] alternativesSelected) {
    boolean allOK = true;
    int nPaths= myAlternativePaths.size();
    alternativesSelected[0]=alternativesSelected[0]+1;
    for (int i=0; i<nPaths; i++) {
        if (alternativesSelected[i]>=myAlternativePaths.get(i).myAlternativeRoutes.size()) {
            alternativesSelected[i]=0;
            if(i<nPaths-1) {
                alternativesSelected[i+1]=alternativesSelected[i+1]+1;
            } else {
                allOK = false;
            }
        }
 //       allOK=allOK & (alternativesSelected[i]<myAlternativePaths.get(i).myAlternativeRoutes.size());
    }
    return allOK;
}
[0, 1, 2]
[0, 1, 3]
[0, 2, 2]
[0, 2, 3]
[1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 2, 3]
public static Stream<int[]> nest(Supplier<IntStream> first, Supplier<IntStream>... streams) {
    Stream<int[]> result = first.get().mapToObj(i -> new int[]{i});

    for (Supplier<IntStream> s : streams) {
        result = nest(result, s);
    }

    return result;
}

private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target) {
    return source.flatMap(b -> target.get().mapToObj(i -> {
        int[] result = new int[b.length + 1];
        System.arraycopy(b, 0, result, 0, b.length);
        result[b.length] = i;
        return result;
    }));
}
public static Stream<int[]> nest(Supplier<IntStream>... streams) {
    final int[] buffer = new int[streams.length];
    Stream<int[]> result = Stream.of(buffer);

    for (int n = 0; n < streams.length; n++) {
        result = nest(result, streams[n], n);
    }

    // Might need to perform a copy here, if indices are stored instead of being consumed right away.
    // return result.map(b -> Arrays.copyOf(b, b.length));
    return result;
}

private static Stream<int[]> nest(Stream<int[]> source, Supplier<IntStream> target, int index) {
    return source.flatMap(b -> target.get().mapToObj(i -> {
        b[index] = i;
        return b;
    }));
}
nest(
    () -> IntStream.range(0, 2),
    () -> IntStream.range(0, 2), 
    () -> IntStream.range(0, 3))
    .forEach(indices -> System.out.println( Arrays.toString(indices)));
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]