是否有一个好的LINQ方法来做笛卡尔积?

时间:2022-08-27 11:03:44

I have a class structure like so:

我的班级结构是这样的:

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

There is one person. He has 1..n dogs. Each dog has 1..n puppies.

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

I want a list of all the possible combination of puppies, taking 1 puppy from each dog. Eg:

我想要一份所有可能的小狗组合的清单,从每只狗身上取一只小狗。例如:

dog 1 puppy A, dog 2 puppy A dog 1 puppy A, dog 2 puppy B dog 1 puppy B, dog 2 puppy A dog 1 puppy B, dog 2 puppy B

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

If it was in sql tables, i'd do something like the following to 'multiply' the tables:

如果它在sql表中,我将做如下操作来“乘”表:

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

Is there some linq-ish way to do this kinda thing???

有什么类似林肯的方式来做这件事吗?

Thanks so much

非常感谢

3 个解决方案

#1


67  

If I understand the question, you want the Cartesian Product of n sets of puppies.

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

It is easy to get the Cartesian Product if you know at compile time how many sets there are:

如果你在编译时知道有多少集,就很容易得到笛卡尔积:

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

Suppose dog1 has puppies p11, p12, dog2 has puppy p21, and dog3 has puppies p31, p32. This gives you

假设狗1有p11, p12,狗2有p21,狗3有p31, p32。这给你

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}

Where each row is an anonymous type. If you do not know at compile time how many sets there are, you can do that with slightly more work. See my article on the subject:

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

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

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

and this * question:

这*问题:

Generating all Possible Combinations

生成所有可能的组合

Once you have the method CartesianProduct<T> then you can say

一旦你有了方法CartesianProduct ,你就可以说

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

to get

得到

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}

Where each row is a sequence of puppies.

每一行都是一排小狗。

Make sense?

有意义吗?

#2


13  

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

狗。加入(小狗、()= > true()= > true,(1、2)= >新Tuple(1、2);

You can do a regular join, but the selectors are both returning the same value, because I want all combinations to be valid. When combining, put both into one tuple (or a different data structure of your choosing).

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

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

This should do a Cartesian product.

这应该是笛卡尔积。

#3


10  

If you want all possible combinations of dog and puppy, you would do a cross join:

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

from dog in Dogs
from puppy in Puppies
select new
{
    Dog = dog,
    Puppy = puppy
}

#1


67  

If I understand the question, you want the Cartesian Product of n sets of puppies.

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

It is easy to get the Cartesian Product if you know at compile time how many sets there are:

如果你在编译时知道有多少集,就很容易得到笛卡尔积:

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

Suppose dog1 has puppies p11, p12, dog2 has puppy p21, and dog3 has puppies p31, p32. This gives you

假设狗1有p11, p12,狗2有p21,狗3有p31, p32。这给你

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}

Where each row is an anonymous type. If you do not know at compile time how many sets there are, you can do that with slightly more work. See my article on the subject:

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

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

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

and this * question:

这*问题:

Generating all Possible Combinations

生成所有可能的组合

Once you have the method CartesianProduct<T> then you can say

一旦你有了方法CartesianProduct ,你就可以说

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

to get

得到

{p11, p21, p31},
{p11, p21, p32},
{p12, p21, p31},
{p12, p21, p32}

Where each row is a sequence of puppies.

每一行都是一排小狗。

Make sense?

有意义吗?

#2


13  

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

狗。加入(小狗、()= > true()= > true,(1、2)= >新Tuple(1、2);

You can do a regular join, but the selectors are both returning the same value, because I want all combinations to be valid. When combining, put both into one tuple (or a different data structure of your choosing).

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

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

This should do a Cartesian product.

这应该是笛卡尔积。

#3


10  

If you want all possible combinations of dog and puppy, you would do a cross join:

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

from dog in Dogs
from puppy in Puppies
select new
{
    Dog = dog,
    Puppy = puppy
}