C#如何在递归调用期间使用yield运算符?

时间:2015-11-06 19:43:06

标签: c# recursion yield

我有一个用于构建数组组合的递归方法。该方法效果很好,但要求在迭代之前将结果数组完全分配到内存中。我读到了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,我没有得到任何结果。我已经尝试了其他处理收益率的方法,但没有一种方法可以“收益”结果(坏双关语)。

1 个答案:

答案 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;
            }
        }
    }
}