C# 如何在递归调用期间使用 yield 运算符?
C# how to use yield operator during recursive call?
我有一个构建数组组合的递归方法。该方法效果很好,但要求在迭代之前将结果数组完全分配到内存中。我了解了 yield 运算符,因为它使用的是 IEnumerator<> ,所以它似乎一次应该 return 一个结果,从而大大减少了内存消耗。我尝试了各种方案来 'yield' 结果。但是,其中 none 是成功的。我想知道如何使用 yield 运算符来达到预期的结果。
这是构建组合的代码:
public static class CombinationArray
{
private static int _resultsIndex;
private static int[][] _results;
public static int GetBinCoeff(int n, int k)
{
int r = 1;
int d;
if (k > n) return 0;
for (d = 1; d <= k; d++)
{
r *= n--;
r /= d;
}
return r;
}
public static int[][] GetCombinations(int[] elements, int length)
{
_resultsIndex = 0;
int numResults = GetBinCoeff(elements.Length, length);
// observe that here I fully allocate the results array[][]:
_results = new int[numResults][];
for (int i = 0; i < numResults; i++)
_results[i] = new int[length];
Combinations(elements, length, 0, new int[length]);
return _results;
}
private static void Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
Array.Copy(result, _results[_resultsIndex++], result.Length);
return;
}
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
Combinations(input, len - 1, i + 1, result);
}
}
}
上面的代码可以这样调用:
[Test]
public void CombinationsUsingArraysOnly()
{
int[] items = {1, 2, 3};
var results = CombinationArray.GetCombinations(items, 2);
for (int i = 0; i < results.GetLength(0); i++)
{
string output = "";
for (int j = 0; j < results[i].Length; j++)
output += results[i][j] + ",";
Console.WriteLine(output);
}
}
结果输出如下:
1,2,
1,3,
2,3,
我尝试了以下方法,但没有成功:
private static IEnumerable<int[]> Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
yield return result;
}
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
Combinations(input, len - 1, i + 1, result);
}
}
...但是当我 'foreach' return 'IEnumerable<>' 时,它的行为就像计数==0 一样,我没有得到任何结果。我尝试了其他处理产量的方法,但其中 none 结果 "yield" 结果(双关语不好)。
您还需要迭代递归调用。在您的代码中,您只有 return 基本情况,而其余的执行没有 return 任何东西。
private static IEnumerable<int[]> Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
yield return result;
}
else
{
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
//// You need to return the results of your recursive call
foreach (var combination in Combinations(input, len - 1, i + 1, result))
{
yield return combination;
}
}
}
}
我有一个构建数组组合的递归方法。该方法效果很好,但要求在迭代之前将结果数组完全分配到内存中。我了解了 yield 运算符,因为它使用的是 IEnumerator<> ,所以它似乎一次应该 return 一个结果,从而大大减少了内存消耗。我尝试了各种方案来 'yield' 结果。但是,其中 none 是成功的。我想知道如何使用 yield 运算符来达到预期的结果。
这是构建组合的代码:
public static class CombinationArray
{
private static int _resultsIndex;
private static int[][] _results;
public static int GetBinCoeff(int n, int k)
{
int r = 1;
int d;
if (k > n) return 0;
for (d = 1; d <= k; d++)
{
r *= n--;
r /= d;
}
return r;
}
public static int[][] GetCombinations(int[] elements, int length)
{
_resultsIndex = 0;
int numResults = GetBinCoeff(elements.Length, length);
// observe that here I fully allocate the results array[][]:
_results = new int[numResults][];
for (int i = 0; i < numResults; i++)
_results[i] = new int[length];
Combinations(elements, length, 0, new int[length]);
return _results;
}
private static void Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
Array.Copy(result, _results[_resultsIndex++], result.Length);
return;
}
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
Combinations(input, len - 1, i + 1, result);
}
}
}
上面的代码可以这样调用:
[Test]
public void CombinationsUsingArraysOnly()
{
int[] items = {1, 2, 3};
var results = CombinationArray.GetCombinations(items, 2);
for (int i = 0; i < results.GetLength(0); i++)
{
string output = "";
for (int j = 0; j < results[i].Length; j++)
output += results[i][j] + ",";
Console.WriteLine(output);
}
}
结果输出如下:
1,2,
1,3,
2,3,
我尝试了以下方法,但没有成功:
private static IEnumerable<int[]> Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
yield return result;
}
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
Combinations(input, len - 1, i + 1, result);
}
}
...但是当我 'foreach' return 'IEnumerable<>' 时,它的行为就像计数==0 一样,我没有得到任何结果。我尝试了其他处理产量的方法,但其中 none 结果 "yield" 结果(双关语不好)。
您还需要迭代递归调用。在您的代码中,您只有 return 基本情况,而其余的执行没有 return 任何东西。
private static IEnumerable<int[]> Combinations(int[] input, int len, int startPosition, int[] result)
{
if (len == 0)
{
yield return result;
}
else
{
for (int i = startPosition; i <= input.Length - len; i++)
{
result[result.Length - len] = input[i];
//// You need to return the results of your recursive call
foreach (var combination in Combinations(input, len - 1, i + 1, result))
{
yield return combination;
}
}
}
}