【问题标题】:Using LINQ to iterate combinations [duplicate]使用 LINQ 迭代组合 [重复]
【发布时间】:2011-12-16 23:56:31
【问题描述】:

可能重复:
Generating all Possible Combinations
Is there a good LINQ way to do a cartesian product?
How to generate combination of N elements with limited supply of 2 each without explicit nested loops

我有一个列表列表,我想迭代所有可能的组合,从每个内部列表中选择一个元素。如果我在编译时知道有多少个列表,这非常简单,但是如果我事先知道会有多少个列表,我该怎么做呢?

如果我有三个列表(并且如果我在编译时知道将恰好有三个列表),并且我想要从三个列表中的每一个中选择单个元素的所有组合,我可以这样做轻松使用 LINQ 查询:

var list1 = new[] { 1, 2 };
var list2 = new[] { 3, 4 };
var list3 = new[] { 5, 6 };
var combinations = from item1 in list1
                   from item2 in list2
                   from item3 in list3
                   select new[] { item1, item2, item3 };
// Results:
// {1, 3, 5}
// {1, 3, 6}
// {1, 4, 5}
// {1, 4, 6}
// {2, 3, 5}
// {2, 3, 6}
// {2, 4, 5}
// {2, 4, 6}

但是当我在编译时不知道会有多少列表时,我怎么能做同样的事情呢?

var lists = new[] {
    new[] { 1, 2 },
    new[] { 3, 4 },
    new[] { 5, 6 } };
var combinations = ???;

// This particular example happens to be the same inputs as above, so it
// has the same expected outputs. But there could be two lists instead,
// or four, so the three hard-coded "from" clauses won't work.

看起来这在 LINQ 中实际上应该是可行的——SelectMany 已经完成了相当于两个嵌套 foreach 循环的操作,所以我需要做的就是执行一堆 SelectMany 调用,然后将所有结果与另一个 SelectMany 结合起来。或者其他的东西。但是当它开始变得像这样时,我的大脑就陷入了困境。我无法掌握如何将这些碎片组合在一起。我什至无法弄清楚外部 SelectMany 调用的泛型类型参数是什么。

如何在编译时不知道会有多少个列表的情况下迭代这些列表并返回所有组合?

(注意:我在上面使用数组的任何地方,我都可以使用 IEnumerable<T> 代替。数组更容易在示例代码中编写,但我希望输出更有可能采用 @ 的形式987654328@ 而不是我在上面的示例输出中显示的int[][]。)

【问题讨论】:

  • 这是你的answer
  • 这不是两个 questions 的重复——这两个问题都在询问固定数量的列表——但实际上这两个问题都包含一个 答案(在这两种情况下都是同一个人的答案!)对于可变数量的列表情况。
  • @Steven,你链接的问题比我的新,所以如果有的话,它是这个问题的副本。

标签: combinations linq


【解决方案1】:

您不使用 SelectMany 来组合 SelectMany 调用;您使用聚合。代码由Eric Lippert 提供(回答比这个更具体的问题,但也给出适合这个问题的一般答案):

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    this IEnumerable<IEnumerable<T>> sequences)
{
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
    return sequences.Aggregate(
        emptyProduct,
        (accumulator, sequence) => 
            from accseq in accumulator 
            from item in sequence 
            select accseq.Concat(new[] {item}) :                         
        );
}

与 Eric 的所有答案一样,他包含了一个 detailed discussion,它根据等效的非 LINQ 代码准确地说明了它的工作原理和原因。

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    • 2013-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    相关资源
    最近更新 更多