Подтвердить что ты не робот

Есть ли хороший способ LINQ для декартового продукта?

У меня есть такая структура класса:

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-ish способ сделать эту вещь?

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

4b9b3361

Ответ 1

Если я понимаю вопрос, вы хотите декартово произведение n наборов щенков.

Легко получить декартово произведение, если во время компиляции вы знаете, сколько наборов существует:

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

Предположим, что у собаки 1 есть щенки 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}

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

Имеют смысл?

Ответ 2

  dogsJoin (щенки,() = > true,() = > true, (один, два) = > новый кортеж (один, два));

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

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

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

Ответ 3

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

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