C# 列出排列(未知编号)

C# 列出排列(未知编号),c#,C#,可能重复: 我有多个列表,可以是2个或3个,最多10个列表,有多个 他们的价值观。现在我需要做的是把所有的 是的 例如,如果我有3个具有以下值的列表: 清单1:3、5、7 清单2:3、5、6 清单3:2,9 我会得到这些组合 3,3,2 3,3,9 3,5,2 等等 现在的问题是,我不能很容易地做到这一点,因为我不知道我有多少个列表,因此确定我需要多少个循环。你可以让一个列表不是很有效,但很容易理解的方法可能是递归地解决这个任务。考虑一种计算 n列表排列的方法。如果您有这样一种方法,那

可能重复:

我有多个列表,可以是2个或3个,最多10个列表,有多个 他们的价值观。现在我需要做的是把所有的 是的

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

  • 清单1:3、5、7
  • 清单2:3、5、6
  • 清单3:2,9
我会得到这些组合

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

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

你可以让一个
列表不是很有效,但很容易理解的方法可能是递归地解决这个任务。考虑一种计算<强> 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);
    }
}
IEnumerable GetAllPermutations(IEnumerable InputList)
{
如果(!inputLists.Any())返回新[]{Enumerable.Empty()};
其他的
{
foreach(GetAllPermutations(inputList.Skip(1))中的var perm)
foreach(inputLists.First()中的变量x)
收益返回新[]{x}.Concat(perm);
}
}

您可能会让这更容易,但这正是我刚才想到的:

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;
}
列表列表=新列表();
添加(新列表(新int[]{3,5,7}));
添加(新列表(新int[]{3,5,6}));
添加(新列表(新int[]{2,9}));
int listCount=lists.Count;
列表索引=新列表();
for(int i=0;i=0&&++index[incrementIndex]>=lists[incrementIndex].Count)
{
索引[递增索引]=0;
递增索引--;
}
//中断条件
如果(递增索引<0)
打破
}

如果我没有完全错的话,这应该是
O(Nm)
,其中
m
是列表的数量,
N
是排列的数量(所有
m
列表长度的乘积)。

非递归解决方案,可以在任何
IEnumerable
s(不仅仅是列表)上工作,而不需要固化它们:

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();
        }
    }
}
公共静态IEnumerable置换(
这是(不可数的来源)
{
//检查源是否为非空、非空?
var enumerables=source.ToArray();
堆栈fe=新堆栈();
Push(枚举数[0].GetEnumerator());
而(fe.Count>0)
{
if(fe.Peek().MoveNext())
{
if(fe.Count==枚举数.Length)
收益率返回新堆栈(fe.Select(e=>e.Current));
其他的
Push(枚举数[fe.Count].GetEnumerator());
}
其他的
{
fe.Pop().Dispose();
}
}
}

另一种选择是,遵循罗林斯的总体思路,以下方法应该可行

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;
}
公共静态IEnumerable置换(此IEnumerable底层)
{
var enumerators=新队列(底层.Select(u=>u.GetEnumerator())
.Where(enumerator=>enumerator.MoveNext());
布尔流=枚举数.Any();
如果(流媒体)
{
可数结果;
IEnumerator finalEnumerator=枚举数.Dequeue();
Func finalAction=b=>b?b:finalEnumerator.MoveNext();
函数交互=
枚举数。反向()
.Select(枚举器=>newfunc(b=>b?b:(枚举器.MoveNext()?true:枚举器.ResetMove()))
。骨料((f1,f2)=>(b=>f1(f2(b));
Enqueue(finalEnumerator);
Func置换作用=
interimAction==null?
最终承诺:
b=>finaliaction(interimation(b));
while(流媒体)
{
结果=新队列(枚举数.Select(枚举数=>enumerator.Current))
流=置换动作(真);
收益结果;
}
}
私有静态布尔重置移动(此IEnumerator底层)
{
Reset();
底层的MoveNext();
返回false;
}

我不这么认为,因为我的问题只是因为“未知”列表的数量n例如,如果我有三个列表,我需要每个循环有三个重叠的列表n实际上,对于任意数量的列表,可能最多2个。因为主列表包含所有列表。当然,除非列表中的值是其他列表。那么这就成了一个问题。是的。如果是这样的情况,则具有值的列表包含lis那么你应该在问题中陈述这一点,以获得更准确的答案;-)我现在明白你的意思了,我编辑了我的代码,这样就可以得到你总共需要做的迭代次数。你可能想从
1
开始,而不是
0
。哦,我确实仔细检查了那个小而可怕的错误。我一直在反复研究这个问题,以确保它在
GetEnumerator
不起作用的情况下能正常工作方法返回相同的东西,在这样做的时候,我想我已经达到了一个程度,它与嵌套的
foreach
循环的实际功能非常相似。好主意,我将+1你,尽管你没有过滤空的枚举数,因此如果你有一个,它将在移动时返回false下一个被弹出,上一个将被移动,然后空枚举数将被推回并循环…可能enumerables=source.Where(e=>
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;
}