C# - 递归函数覆盖输出列表

时间:2014-11-29 08:33:58

标签: c# recursion combinations

我正在上课,找到N个列表的每个组合。组合算法似乎完美无缺(当我单步执行时),但我无法保存结果。我想将所有生成的数组存储在另一个列表中以供稍后使用,但是当我执行最后一个数组时会覆盖所有以前的数组。示例输入/输出和我的代码如下。有没有人有任何想法如何解决这个问题? (我已尝试过具有相同结果的参考参数和全局列表。)

/*
 Input: A B C
          X Y

  Expected Output: A X
                   A Y
                   B X
                   B Y
                   C X
                   C Y

  Actual Output:   C Y
                   C Y
                   C Y
                   C Y
                   C Y
                   C Y
*/


public class Combination<T>{
    private static void Combine(T[] res, int ix, List<List<T>> data, ref List<T[]> allCombos){
        foreach (T v in data[ix]){
            res[ix] = v;
            if (ix >= data.Count - 1){
                allCombos.Add(res);
            }else{
                Combine(res, ix + 1, data, ref allCombos);
            }
        }
    }

    public static List<T[]> Combine(List<List<T>> data){
        List<T[]> allCombos = new List<T[]>();
        Combine(new T[data.Count], 0, data, ref allCombos);
        return allCombos;
    }
}

4 个答案:

答案 0 :(得分:2)

这里的主要问题是您只分配一个T[]实例。您只是一遍又一遍地添加到List<T[]>

而不是:

allCombos.Add(res);

你应该试试这个:

allCombos.Add(res.ToArray());

每次将数组添加到列表中时,都会创建一个新的数组副本。

答案 1 :(得分:0)

试试这个。我认为这应该有效。我不是在终端上测试它。

public class Combination<T>
{
    static T[] res;
    private static void Combine(int ix, List<List<T>> data, ref List<T[]> allCombos)
    {
        foreach (T v in data[ix])
        {
            res[ix] = v;
            if (ix >= data.Count - 1)
            {
                allCombos.Add(res);
            }
            else
            {
                Combine(res, ix + 1, data, ref allCombos);
            }
        }
    }

public static List<T[]> Combine(List<List<T>> data)
{
    List<T[]> allCombos = new List<T[]>();
    res = new  T[data.Count];
    Combine(0, data, ref allCombos);
    return allCombos;
}

}

答案 2 :(得分:0)

问题是res参数在每次迭代中被重用和覆盖。这是我的解决方案。

using System;
using System.Linq;
using System.Collections.Generic;
....

    private IEnumerable<T[]> Combine<T>(IEnumerable<T[]> data)
    {
        if (!data.Any())
            yield break;

        var head = data.First();
        var tail = Combine(data.Skip(1));
        foreach (var e in head)
        {
            var list = new T[] {e};
            if (!tail.Any())
                yield return list;
            else
            {
                foreach (var t in tail)
                {
                    yield return list.Concat(t).ToArray();
                }
            }
        }
    }

答案 3 :(得分:0)

记录下来,我遇到了类似的问题,最近发布了一系列自定义对象。对我来说,基本上是创建一个新对象,并使用原来用于覆盖的对象(“ subTree”)作为基础。

//Do this
TreeView newTree= new TreeView { 
name = subTree.name,
children = subTree.children
};
actualTree.Add(newTree);
//Not this
actualTree.Add(subTree)

如果我不这样做,每次尝试将TreeView元素添加到“ actualTree”列表中时,我都会得到最后一个“ subTree”对象。解决方案是,每当必须向列表中添加元素时,就使用其他对象所需的值创建一个新对象,这样就不必总是添加同一对象。