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

换句话说,我可以做类似的事情

for() { for { for { } } } 

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

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

听起来你可能想看看递归。

jjnguy是对的; 递归可让您动态创建可变深度嵌套。 但是,如果没有更多工作,您无法访问外层数据。 “嵌入式嵌套”案例:

 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** } } } 

将变量ijk保持在最内层体的范围内。

这是一个快速破解:

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

IAction接口规定了受控操作的作用,该操作将索引数组作为其act方法的参数。

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

这是一个示例用法:

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

和执行的(部分)输出:

 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 

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

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

例如:

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

相当于:

 for (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循环嵌套在彼此内部,而无需弄清楚它们应该如何组合在一起。

2015年编辑:与前一个咒语一样,我做了以下方案来处理这个问题; https://github.com/BeUndead/NFor

用法如下

 public static void main(String... args) { NFor 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] 

它还支持除了lessThan之外的条件。 其中的用法(使用import static NFor.*; ):

 NFor 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] 

显然,支持不同长度和不同类(所有盒装,数字基元)的循环。 默认值(如果未指定)来自(0,…)。by(1,…); 但必须指定一个到(…)。

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

这个基本前提是每次转向简单地推进’指数’而不是使用递归。

问题需要更多规范。 也许递归会对你有所帮助,但请记住,递归几乎总是迭代的替代方法,反之亦然。 可能是2级嵌套循环足以满足您的需求。 请告诉我们您要解决的问题。

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

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

现在,让我们将这个想法扩展到列表。 如果您在嵌套循环中迭代三个列表,这只是一种使用单个循环迭代列表产品的更复杂方法。 但是,您如何表达三个列表的产品?

首先,我们需要一种表达类型产品的方法。 两种类型XY的乘积可以表示为类似P2的通用类型。 这只是一个由两个值组成的值,一个是X型,另一个是Y型。 它看起来像这样:

 public abstract class P2 { public abstract A _p1(); public abstract B _p2(); } 

对于三种类型的产品,我们只有P3 ,具有明显的第三种方法。 然后,通过在产品类型上分发List仿函数来实现三个列表的产品。 所以ListListList的乘积就是List> 。 然后,您可以使用单个循环遍历此列表。

Functional Java库具有List类型,该类型支持使用第一类函数和产品类型(P2,P3等,也包含在库中)将列表相乘。

例如:

 for (String x : xs) { for (String y : ys) { for (String z : zs) { doSomething(x, y, z); } } } 

相当于:

 for (P3 p : xs.map(P.p3()).apply(ys).apply(zs)) { doSomething(p._1(), p._2(), p._3()); } 

继续使用Functional Java,您可以将doSomething打造成一流的,如下所示。 假设doSomething返回一个String:

 public static final F, String> doSomething = new F, String>() { public String f(final P3 p) { return doSomething(p._1(), p._2(), p._3()); } }; 

然后你可以完全消除for循环,并收集doSomething的所有应用程序的结果:

 List s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething); 

如果你有一个通用的嵌套循环结构,如:

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

其中i0,i1,i2,...,id是循环变量, d是嵌套循环的深度。

等效递归解决方案:

 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 

计数器是一个大小为d的数组,分别表示对应的变量i0,i1,i2,...idint counters[d]

 nestedToRecursion(counters,0); 

类似地,我们可以转换其他变量,如初始化递归或结束使用数组,即我们可以有initial[d], ending[d]

我可以在Java 7中提出的最新的通用方法是

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

支持此function的实现是:

 /** * 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 
 String fors(int n){ StringBuilder bldr = new StringBuilder(); for(int i = 0; i < n; i++){ for(int j = 0; j < i; j++){ bldr.append('\t'); } bldr.append("for() {\n"); } for(int i = n-1; i >= 0; i--){ for(int j = 0; j < i; j++){ bldr.append('\t'); } bldr.append("}\n"); } return bldr.toString(); } 

创建一个漂亮的嵌套for循环骨架;-)不完全严重,我知道递归解决方案会更优雅。

 public void recursiveFor(Deque 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); } } 

示例电话:

 int[] ranges = {2, 2, 2}; recursiveFor(new ArrayDeque(), ranges, ranges.length); 

我第一次回答问题,但我觉得我需要分享这个信息

 for (x = 0; x < base; ++x) { for (y = 0; y < loop; ++y) { DoSomething(); } } 

相当于

 for (x = 0; x < base*loop; ++x){ DoSomething(); } 

因此,如果你想要n个嵌套,可以使用baseloop之间的划分来编写它,这样看起来就像这样简单:

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

所以,如果你打字printer(10, 2); 它会打印出来:

 00 01 02 03 04 ... 97 98 99 

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

 void variDepth(int depth, int n, int i) { cout<<"\nd = "<