有没有一种很好的 LINQ 方法来做笛卡尔积?

Posted

技术标签:

【中文标题】有没有一种很好的 LINQ 方法来做笛卡尔积?【英文标题】:Is there a good LINQ way to do a cartesian product? 【发布时间】:2010-11-01 22:43:15 【问题描述】:

我有一个这样的类结构:

Person
Dogs (dog 1, dog 2, etc)
Puppies (puppy A, puppy B, etc)

只有一个人。他有1..n条狗。每只狗有 1..n 只小狗。

我想要一份所有可能的小狗组合的列表,从每只狗中取出 1 只小狗。例如:

狗 1 小狗 A,狗 2 小狗 A 狗 1 小狗 A,狗 2 小狗 B 狗 1 小狗 B,狗 2 小狗 A 狗 1 小狗 B,狗 2 小狗 B

如果它在 sql 表中,我会执行以下操作来“乘以”表:

select * from puppies a, puppies b where a.parent='dog1' and b.parent='dog2'

有没有一些类似 linq 的方式来做这种事情???

非常感谢

【问题讨论】:

【参考方案1】:

如果我理解这个问题,你想要 n 组小狗的 笛卡尔积

如果您在编译时知道有多少个集合,则很容易获得笛卡尔积:

from p1 in dog1.Puppies
from p2 in dog2.Puppies
from p3 in dog3.Puppies
select new p1, p2, p3;

假设 dog1 有小狗 p11、p12,dog2 有小狗 p21,dog3 有小狗 p31、p32。这给了你

p11, p21, p31,
p11, p21, p32,
p12, p21, p31,
p12, p21, p32

每一行都是匿名类型。如果您在编译时不知道有多少个集合,您可以做更多的工作。请参阅我关于该主题的文章:

http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/

还有这个 *** 问题:

Generating all Possible Combinations

一旦你有了CartesianProduct<T>的方法,你就可以说

CartesianProduct(from dog in person.Dogs select dog.Puppies)

得到

p11, p21, p31,
p11, p21, p32,
p12, p21, p31,
p12, p21, p32

每行是一系列小狗。

有意义吗?

【讨论】:

那么我说这是递归编程的替代方案是否正确? @Nick:我认为说这是 命令式 编程的替代方案更贴切。 LINQ 的重点是您说出您想要的内容——您以声明方式 进行编程——编译器根据可用的运行时库确定如何执行此操作。如果这些库使用递归编程或迭代编程来完成它们的工作,那就是它们的业务。 这是有道理的,但是在我问***.com/questions/5348485/… 的这个问题中,我无法弄清楚如何在不使用递归编程的情况下使用 LINQ 获得结果,有没有更短的方法? @Nick:当然有。据我了解,您的问题无需递归即可轻松解决。我会发布一个答案。【参考方案2】:

dog.Join(puppies, () => true, () => true, (one, two) => new Tuple(one, two));

您可以进行常规连接,但选择器都返回相同的值,因为我希望所有组合都有效。组合时,将两者放入一个元组(或您选择的不同数据结构)。

leftSide.SelectMany((l) => rightSide, (l, r) => new Tuple(l, r));

这应该是笛卡尔积。

【讨论】:

这是很多问题。 (1) SelectMany 的目的不是将多个 IEnumerable 折叠成一个 IEnumerable 吗?是的,尽管它当然不止于此。从“序列”的角度来看,SelectMany 是在后端有投影的笛卡尔积算子。从更一般的“monad”的角度来看,SelectMany 是对 monad 模式的 Bind 操作。 (2) “我没有找到将查询理解笛卡尔积转换为流畅语法的方法” - 我建议您参考 C# 4.0 规范的第 7.16.2.4 节,该节提供了详细的解释如何进行翻译。 (3) join 不是定义为笛卡尔积的有限集合吗?是的,联接在逻辑上是笛卡尔积的过滤器。然而,它不是实现的。 Join 针对等值连接情况进行了优化; LINQ to Objects 实现在幕后积极构建哈希表,以便在结果集远小于其过滤的叉积的情况下有效地实现连接相等语义。如果您想要的是笛卡尔积,那么不要使用旨在过滤笛卡尔积的昂贵设备;只需生成产品! (4) 我是否缺少操作员?不,据我所知。 (5) from 子句是否只等同于 foreach 子句,还是有单独的运算符?我不知道这个问题是什么意思。没有“foreach 子句”之类的东西,当您说“等价”时,我不知道您在描述哪些集合上的等价关系。你能澄清一下这个问题吗?【参考方案3】:

如果你想要所有可能的狗和小狗组合,你会做一个交叉连接:

from dog in Dogs
from puppy in Puppies
select new

    Dog = dog,
    Puppy = puppy

【讨论】:

我实际上想要 N 组小狗的所有可能组合,但感谢您让我走上正轨。

以上是关于有没有一种很好的 LINQ 方法来做笛卡尔积?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 excel 中执行交叉连接或笛卡尔积?

Tensorflow 中的笛卡尔积

两个数据源的笛卡尔积

数据库:笛卡尔乘积到底是域乘域,还是元组乘元组?

Erlang List对笛卡尔积的理解

使用火花的笛卡尔积