列出排列(未知数)

时间:2012-11-08 10:11:30

标签: c#

  

可能重复:
  Combination of List<List<int>>

我有多个列表,可能是2个或3个最多10个列表,有多个 其中的价值观。现在我需要做的是获得所有的组合 他们。

例如,如果我有3个包含以下值的列表:

  • 清单1:3,5,7
  • 清单2:3,5,6
  • 清单3:2,9

我会得到这些组合

  • 3,3,2
  • 3,3,9
  • 3,5,2 等。

现在问题是我不能轻易做到这一点,因为我不知道我有多少个列表,因此确定我需要多少个循环。

5 个答案:

答案 0 :(得分:2)

你可能会让事情变得更容易,但这就是我刚才想到的:

List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int>(new int[] { 3, 5, 7 }));
lists.Add(new List<int>(new int[] { 3, 5, 6 }));
lists.Add(new List<int>(new int[] { 2, 9 }));

int listCount = lists.Count;
List<int> indexes = new List<int>();
for (int i = 0; i < listCount; i++)
    indexes.Add(0);

while (true)
{
    // construct values
    int[] values = new int[listCount];
    for (int i = 0; i < listCount; i++)
        values[i] = lists[i][indexes[i]];

    Console.WriteLine(string.Join(" ", values));

    // increment indexes
    int incrementIndex = listCount - 1;
    while (incrementIndex >= 0 && ++indexes[incrementIndex] >= lists[incrementIndex].Count)
    {
        indexes[incrementIndex] = 0;
        incrementIndex--;
    }

    // break condition
    if (incrementIndex < 0)
        break;
}

如果我没有完全错误,那么O(Nm)应为m,其中N为列表数,m为排列数(所有{{1}长度的乘积列表)。

答案 1 :(得分:1)

你可以制作一个List<List<yourValueType> mainlist来放置所有列表。 然后用一个简单的

int numberOfIterations = 1;
foreach(var item in mainlist)
{
    numberOfIterations *= item.Count;
}

这将获得你必须总共执行的迭代量。

答案 2 :(得分:1)

非递归解决方案适用于任何IEnumerable(不仅仅是列表)而不会加固它们:

public static IEnumerable<IEnumerable<T>> Permutations<T>(
    this IEnumerable<IEnumerable<T>> source)
{
    // Check source non-null, non-empty?

    var enumerables = source.ToArray();
    Stack<IEnumerator<T>> fe = new Stack<IEnumerator<T>>();
    fe.Push(enumerables[0].GetEnumerator());

    while (fe.Count > 0)
    {
        if (fe.Peek().MoveNext())
        {
            if (fe.Count == enumerables.Length)
                yield return new Stack<T>(fe.Select(e => e.Current));
            else
                fe.Push(enumerables[fe.Count].GetEnumerator());
        }
        else
        {
            fe.Pop().Dispose();
        }
    }
}

答案 3 :(得分:0)

效率不高但很容易理解的方法可能是递归地解决这个任务。考虑一种计算 N 列表的排列的方法。如果您有这样的方法,那么您可以通过将 N 列表的所有排列与最后一个列表中的每个数字组合,轻松计算 N + 1 列表的排列。您还应该处理 0 列表排列的极端情况。然后实现似乎很简单:

IEnumerable<IEnumerable<T>> GetAllPermutations<T>(IEnumerable<IEnumerable<T>> inputLists)
{
    if (!inputLists.Any()) return new [] { Enumerable.Empty<T>() };
    else
    {
        foreach (var perm in GetAllPermutations(inputLists.Skip(1)))
            foreach (var x in inputLists.First())
                yield return new[]{x}.Concat(perm);
    }
}

答案 4 :(得分:0)

作为替代方案,遵循一般的想法,以下应该有效

public static IEnumerable<IEnumerable<T>> Permutations<T> (this IEnumerable<IEnumerable<T>> underlying)
{
    var enumerators = new Queue<IEnumerator<T>>(underlying.Select(u => u.GetEnumerator())
                                                          .Where(enumerator => enumerator.MoveNext());
    Boolean streaming = enumerators.Any();
    if(streaming)
    {
        IEnumerable<T> result;

        IEnumerator<T> finalEnumerator = enumerators.Dequeue();
        Func<Boolean,Boolean> finalAction = b => b ? b : finalEnumerator.MoveNext();

        Func<Boolean,Boolean> interimAction = 
         enumerators.Reverse()
                    .Select(enumerator => new Func<Boolean,Boolean>(b => b ? b : (enumerator.MoveNext() ? true : enumerator.ResetMove())))
                    .Aggregate((f1,f2) => (b => f1(f2(b)));
        enumerators.Enqueue(finalEnumerator);

        Func<Boolean,Boolean> permutationAction = 
                              interimAction == null ? 
                              finalAction :
                              b => finalAction(interimAction(b));

        while(streaming)
        {
              result = new Queue<T>(enumerators.Select(enumerator => enumerator.Current))
              streaming = permutationAction(true);
              yield return result;
        }
}

private static Boolean ResetMove<T>(this IEnumerator<T> underlying)
{
     underlying.Reset();
     underlying.MoveNext();
     return false;
}