【问题标题】:Two approaches to Cartesian product of a collection of lists using LINQ使用 LINQ 对列表集合的笛卡尔积的两种方法
【发布时间】:2014-09-04 15:22:46
【问题描述】:

我需要创建一组列表的笛卡尔积。例如我有:

{ {4,3,7}, {1,2,9}, {5,8} }

我需要: {4,1,5}, {4,1,8}, {3,1,5}, {3,1,8}, ... , {7,9,8}

到目前为止,我了解到您可以使用以下方法来做到这一点:

var lists = new List<List<int>>
{ 
    new List<int> { 4, 3, 7},
    new List<int> { 1, 2, 9},
    new List<int> { 5, 8},
};

IEnumerable<IEnumerable<int>> empty = new[] { Enumerable.Empty<int>() };
var agg = lists.Aggregate(
    empty,
    (acc, next) 
=>  
    (from ac in acc
    from n in next
    select ac.Concat(new[] {n})));

然而,当我最初实现这个时,我是这样实现的:

var lists = new List<List<int>>
{ 
    new List<int> { 4, 3, 7},
    new List<int> { 1, 2, 9},
    new List<int> { 5, 8},
};

var agg = lists.Aggregate(
    new List<List<int>>() {new List<int> {}},
    (acc, next) 
=>  
    (from ac in acc
    from n in next
    select ac.Add(n)).ToList());

此特定实现无法编译并出现此错误:

“System.Collections.Generic.List”类型的表达式不是 在带有源的查询表达式中的后续 from 子句中允许 类型 'System.Collections.Generic.List>'。 调用“SelectMany”时类型推断失败。

我对这个错误消息有点困惑。我不明白为什么该位置不允许使用List

【问题讨论】:

  • 试试 Eric Lippert 的博客文章:blogs.msdn.com/b/ericlippert/archive/2010/06/28/…
  • 你知道有多少个列表还是N个列表?
  • @DavidG 感谢 linq。我已经读过那篇文章,我想这就是我记得使用Aggregate 的方式。我的问题不是关于如何做笛卡尔积,而是关于上面提到的错误。
  • @terrybozzio 这是任意数量的项目(N 项目)。

标签: c# linq generics cartesian-product


【解决方案1】:

错误消息的第一部分有些误导。以下将编译并正常工作:

var agg = lists.Aggregate(
    new List<List<int>>(),
    (acc, next) 
=>  
    (from ac in acc
    from n in next
    // select ac.Add(n)).ToList());
    select ac.Concat(new[] {n}).ToList()).ToList());

真正的问题在于select ac.Add(n)。 select 子句必须返回一个值(在本例中为 List&lt;int&gt;),但您对 List&lt;T&gt;.Add 的调用会修改原始列表并返回 void。

在底层,LINQ 尝试将此 LINQ 表达式转换为(除其他外)对Enumerable.SelectMany 的调用。编译器传递的参数之一是生成的 lambda 表达式,它返回 ac.Add(n)(即 void)。编译器尝试根据SelectMany 的可用重载来推断生成的lambda 的类型,但是没有兼容的重载,因此无法确定lambda 的类型。因此出现错误消息“在调用 'SelectMany' 时类型推断失败。”。

Add 一样,大多数List&lt;T&gt; 方法通常不适合使用LINQ 进行函数式编程,这就是首选解决方案仅依赖IEnumerable&lt;T&gt; 及其与LINQ 相关的扩展方法的原因。

【讨论】:

  • 很好的答案。我怀疑是这种情况,但无法像您在那里那样连接点。这说得通。如果有更多信息,我会等待更多答案:)
猜你喜欢
  • 1970-01-01
  • 2012-01-03
  • 2020-07-05
  • 2012-09-07
  • 2015-01-28
  • 2016-04-17
  • 2012-03-24
  • 1970-01-01
相关资源
最近更新 更多