我有一个用于构建数组组合的递归方法。该方法效果很好,但要求在迭代之前将结果数组完全分配到内存中。我读到了yield运算符,因为它使用的是IEnumerator<>它似乎应该一次返回一个结果,大大减少内存消耗。我尝试了各种方案来“产生”结果。但是,它们都没有成功。我想知道如何使用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'返回'IEnumerable&lt;&gt;'时它就好像计数== 0,我没有得到任何结果。我已经尝试了其他处理收益率的方法,但没有一种方法可以“收益”结果(坏双关语)。
答案 0 :(得分:1)
您还需要迭代递归调用。在您的代码中,您只返回基本案例,而其余的执行不会返回任何内容。
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;
}
}
}
}