【问题标题】:Lists permutations (unknown number) [duplicate]列出排列(未知数)[重复]
【发布时间】:2012-11-08 10:11:29
【问题描述】:

可能重复:
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 等等。

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

【问题讨论】:

  • 我不这么认为,因为我的问题只是由于列表数量“未知”

标签: c#


【解决方案1】:

你可能会更容易,但这就是我刚才的想法:

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 列表的长度的乘积)。

【讨论】:

    【解决方案2】:

    您可以创建一个List&lt;List&lt;yourValueType&gt; mainlist,将所有列表放入其中。 然后用一个简单的

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

    这将获得您总共必须执行的迭代次数。

    【讨论】:

    • 不,例如,如果我有三个列表,我需要三个重叠的 foreach 循环
    • 不是真的,对于任意数量的列表可能最多 2 个。由于主列表包含所有内容。除非您的列表中的值当然是其他列表。然后它成为一个问题是的。如果您的带有值的列表也包含列表,那么您应该在问题中说明这一点以获得更准确的答案;-)
    • 我现在明白你的意思了,我编辑了我的代码,所以它会得到你必须做的总迭代次数。
    • 您可能希望以1 开头,而不是0
    • 哦,肯定是检查了那个小而可怕的错误。 tnx
    【解决方案3】:

    非递归解决方案,适用于任何IEnumerables(不仅仅是列表),无需固化它们:

    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();
            }
        }
    }
    

    【讨论】:

    • 我一直在玩这个,以确保如果GetEnumerator 并不总是返回相同的东西,它可以工作,这样做我想我已经得到了这个它与嵌套的 foreach 循环的真正作用非常相似。
    • 好主意我会 +1 你,虽然你没有过滤空的枚举,因此如果你有一个它会在 movenext 弹出时返回 false,前一个将被移动,然后空枚举器将被推回并循环......也许 enumerables = source.Where(e => e.Any()).ToArray(); ?
    • @user1793607 如果您在foreach 循环堆栈中有一个空的可枚举项,您也不会得到任何输出,我想效仿——您总是可以在之前过滤掉任何空的可枚举项你叫这个。
    • 很公平。在微优化说明上,我想知道 return new Stack(fe.Select(e => e.Current)) 是否会更快?
    • @user1793607 你是对的,这将节省缓冲它们,反转它们并再次缓冲它们。
    【解决方案4】:

    不是很有效但很容易理解的方法可能是递归地解决这个任务。考虑一种计算 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);
        }
    }
    

    【讨论】:

    • 这很好,但您能否提供一个使用此解决方案的示例,您可以使用多种类型,而不仅仅是 int?
    【解决方案5】:

    作为替代方案,遵循 rawlings 的一般想法,以下应该可行

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

    【讨论】:

      猜你喜欢
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-11-03
      相关资源
      最近更新 更多