Есть ли хороший способ LINQ сделать декартово произведение? - PullRequest
53 голосов
/ 02 ноября 2010

У меня есть структура классов, например:

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

Есть один человек. У него 1.n собак. У каждой собаки есть 1..n щенков.

Я хочу список всех возможных комбинаций щенков, по 1 щенку от каждой собаки. Например:

собака 1 щенок А, собака 2 щенок А собака 1 щенок А, собака 2 щенок Б собака 1 щенок Б, собака 2 щенок А собака 1 щенок Б, собака 2 щенок Б

Если бы это было в таблицах sql, я бы сделал что-то вроде следующего, чтобы «умножить» таблицы:

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

Есть ли какой-нибудь linq-ish способ сделать такую ​​вещь ???

Большое спасибо

Ответы [ 3 ]

79 голосов
/ 02 ноября 2010

Если я понимаю вопрос, вы хотите декартово произведение из 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/

и вопрос StackOverflow:

Генерация всех возможных комбинаций

Если у вас есть метод CartesianProduct<T>, вы можете сказать

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

чтобы получить

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

Где каждый ряд представляет собой последовательность щенков.

Имеет смысл?

18 голосов
/ 02 ноября 2010

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

Можно выполнить обычное объединение, но оба селектора возвращают одно и то же значение, потому что я хочу, чтобы все комбинации были действительными. При объединении поместите оба в один кортеж (или другую структуру данных по вашему выбору).

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

Это должно быть декартово произведение.

13 голосов
/ 02 ноября 2010

Если вам нужны все возможные комбинации собак и щенков, вы должны сделать перекрестное соединение:

from dog in Dogs
from puppy in Puppies
select new
{
    Dog = dog,
    Puppy = puppy
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...