有没有一个很好的LINQ方式来做笛卡尔积?

Chr*_*ris 56 c# sql linq asp.net cartesian-product

我有这样的类结构:

Person
Dogs (dog 1, dog 2, etc)
Puppies (puppy A, puppy B, etc)
Run Code Online (Sandbox Code Playgroud)

有一个人.他有1只狗.每只狗有1只小狗.

我想列出所有可能的小狗组合,从每只狗中取一只小狗.例如:

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

如果它是在sql表中,我会做类似以下的事情来"乘以"表:

select * from puppies a, puppies b where a.parent='dog1' and b.parent='dog2'
Run Code Online (Sandbox Code Playgroud)

是否有一些linq-ish方式来做这种事情???

非常感谢

Eri*_*ert 85

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

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

from p1 in dog1.Puppies
from p2 in dog2.Puppies
from p3 in dog3.Puppies
select new {p1, p2, p3};
Run Code Online (Sandbox Code Playgroud)

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

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}
Run Code Online (Sandbox Code Playgroud)

每行是匿名类型.如果您在编译时不知道有多少集,那么您可以稍微多做一些工作.看我关于这个主题的文章:

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

这个StackOverflow问题:

生成所有可能的组合

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

CartesianProduct(from dog in person.Dogs select dog.Puppies)
Run Code Online (Sandbox Code Playgroud)

要得到

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}
Run Code Online (Sandbox Code Playgroud)

每排是一系列小狗.

合理?

  • @Nick:我认为这是*命令式*编程的替代方案会更加密切相关.LINQ的重点在于你说出你想要的东西 - 你以声明方式编程* - 并且编译器根据可用的运行时库计算出如何编写它.如果这些库使用递归编程或迭代编程来完成它们的工作,那就是他们的业务. (2认同)

McK*_*Kay 18

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

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

leftSide.SelectMany((l) => rightSide, (l, r) => new Tuple(l, r));
Run Code Online (Sandbox Code Playgroud)

这应该是笛卡尔积.

  • 那是很多问题.(1)是不是SelectMany要将多个IEnumerable <T>折叠成一个IEnumerable <T>?是的,虽然它当然不仅仅是那个.从"序列"的角度来看,SelectMany是笛卡尔积运算符,后端有投影.从更一般的"monad"观点来看,SelectMany是monad模式的Bind操作. (3认同)
  • (2)"我找不到将查询理解Cartesian产品翻译成流利语法的方法" - 我将参考C#4.0规范的7.16.2.4节,它提供了如何进行翻译的详细说明. (3认同)
  • (3)不将连接定义为笛卡尔积的有限集合吗?是的,连接在逻辑上是笛卡尔积的过滤器.但是,这不是*实现的方式.*Join针对equijoin案例进行了优化; LINQ to Objects实现在幕后积极地构建哈希表,以便在结果集远小于它正在过滤的交叉产品的情况下有效地实现连接相等语义.如果您想要的是笛卡尔积,那么请不要使用设计用于过滤笛卡尔积的昂贵设备; 只是生成产品! (3认同)
  • (4)我错过了一个操作员吗?不,不是我的知识. (2认同)
  • (5)from子句只相当于foreach子句,还是有单独的运算符?我不知道这个问题意味着什么.没有"foreach子句"这样的东西,我不知道当你说"等价"时,你描述了哪些集合描述了等价关系.你能澄清一下这个问题吗? (2认同)

And*_*tad 14

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

from dog in Dogs
from puppy in Puppies
select new
{
    Dog = dog,
    Puppy = puppy
}
Run Code Online (Sandbox Code Playgroud)