Есть ли хороший способ 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 способ сделать эту вещь?
Большое спасибо
Ответы
Ответ 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
}