递归代替多个嵌套的 for 循环
本文关键字:for 循环 嵌套 递归 | 更新日期: 2023-09-27 18:32:17
我在尝试更新嵌套的 for 循环以使用递归时遇到了一些问题。使用递归时,是否可以从较早的 for 循环访问 a、b 和 c 变量?下面是一个简单的示例,说明 im 试图转换为递归调用的内容。
for(int a= 0; a < 10; a++)
{
for(int b = 0; b < 20; b++)
{
for(int c = 0; c < 10; c++)
{
int[] indexes = new int[3]{a,b,c}
collection.add(indexes);
}
}
}
编辑:解决方案需要能够在运行时进行调整,以便用户可以选择所需的级别数。
这是一个递归解决方案(使用函数式编程风格):
public static IEnumerable<IEnumerable<int>> GetCombinations(IEnumerable<int> limits)
{
if (limits.Any() == false)
{
// Base case.
yield return Enumerable.Empty<int>();
}
else
{
int first = limits.First();
IEnumerable<int> remaining = limits.Skip(1);
IEnumerable<IEnumerable<int>> tails = GetCombinations(remaining);
for (int i = 0; i < first; ++i)
foreach (IEnumerable<int> tail in tails)
yield return Yield(i).Concat(tail);
}
}
// Per http://stackoverflow.com/q/1577822
public static IEnumerable<T> Yield<T>(T item)
{
yield return item;
}
样品使用:
var sequences = GetCombinations(new [] { 5, 3, 2, 4 /* ... */ });
foreach (var sequence in sequences)
Console.WriteLine(string.Join(", ", sequence));
/* Output:
0, 0, 0, 0
0, 0, 0, 1
0, 0, 0, 2
0, 0, 0, 3
0, 0, 1, 0
0, 0, 1, 1
0, 0, 1, 2
0, 0, 1, 3
0, 1, 0, 0
0, 1, 0, 1
0, 1, 0, 2
... */
对于OP的特定场景(将数组添加到collection
):
var sequences = GetCombinations(new [] { 10, 20, 10 });
collection.AddRange(sequences.Select(s => s.ToArray()));
好的,试试这个
static void AddToCollectionRecursive(
List<int[]> collection,
params int[] counts)
{
AddTo(collection, new List<int>(), counts, counts.Length - 1);
}
static void AddTo(
List<int[]> collection,
IEnumerable<int> value,
IEnumerable<int> counts,
int left)
{
for (var i = 0; i < counts.First(); i++)
{
var list = value.ToList();
list.Add(i);
if (left == 0)
{
collection.Add(list.ToArray());
}
else
{
AddTo(collection, list, counts.Skip(1), left - 1);
}
}
}
用法是这样的AddToCollectionRecursive(collection, 10, 20, 10);
.
这样的东西就可以了:
public void CreateIndexes(int a, int b, int c, Collection collection)
{
if(c == 10) {b++; c = 0;}
if(b == 20) {a++; b = 0;}
if(a == 10) return;
int[] indexes = new int[3]{a,b,c}
collection.add(indexes);
c++;
CreateIndexes(a, b, c, collection);
}
在我的头顶上,即没有经过测试,这样的事情可能会起作用:
List<int[]> collection = new List<int[]>();
private void AddValues(int a, int b, int c)
{
collection.Add(new[] { a, b, c });
if (c < 10)
{
c++;
AddValues(a, b, c);
}
if (b < 20)
{
b++;
c = 0;
AddValues(a, b, c);
}
if (a < 10)
{
a++;
b = 0;
c = 0;
AddValues(a, b, c);
}
}
通过调用开始它:
AddValues(0, 0, 0);
好吧,我认为如果您使用递归解决此问题,它将消耗更多的内存和其他资源!
但是有我的建议:
private void FunctionName(int a, int b, int c, List<int[]> list)
{
if (a<10)
{
if (b<20)
{
if (c<10)
{
list.Add(new[] { a, b, c });
c++;
FunctionName(a,b,c,list);
}
else
{
c=0;
b++;
FunctionName(a,b,c,list);
}
}
else
{
b=0;
a++;
FunctionName(a,b,c,list);
}
}
}
你像这样调用:函数名称(0,0,0,列表)。
希望它有效! ^^
此解决方案对要在叶子上完成的工作执行操作:
void ForEachCombo(int from, int to, int nrLevels, Action<int[]> action)
{
int[] d = new int[nrLevels];
InnerFor(from, to, 0);
void InnerFor(int from, int to, int level)
{
if (level == nrLevels)
action(d);
else
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
InnerFor(d[level] + 1, to, level + 1);
}
}
像这样使用:
ForEachCombo(0, 9, 3, (d) =>
{
Console.WriteLine(string.Join(", ", d));
});
// Output
0, 1, 2
0, 1, 3
0, 1, 4
0, 1, 5
...
6, 7, 9
6, 8, 9
7, 8, 9
//
如果你愿意,你可以通过这样写来保存一个递归级别:
void ForEachCombo(int from, int to, int nrLevels, Action<int[]> action)
{
int[] d = new int[nrLevels];
InnerFor(from, to, 0);
void InnerFor(int from, int to, int level)
{
if (level == nrLevels - 1)
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
action(d);
else
for (d[level] = from; d[level] <= to - nrLevels + level + 1; d[level]++)
InnerFor(d[level] + 1, to, level + 1);
}
}