2010-11-01 1 views
41

У меня есть структура класса, как так:Есть ли способ LINQ сделать декартовой продукт?

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-иш способ сделать это любопытное дело ???

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

ответ

62

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

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

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 вопрос:

Generating all Possible Combinations

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

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

получить

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

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

Имеют смысл?

+0

Бинго! Спасибо за помощь. – Chris

+0

Так было бы правильно сказать, что это альтернатива рекурсивному программированию? –

+2

@Nick: Я думаю, было бы более разумно сказать, что это альтернатива * императивному программированию. Точка LINQ - это то, что вы говорите, что хотите - вы программно декларативно *, а компилятор определяет, как это сделать на основе доступных библиотек времени исполнения. Если эти библиотеки выполняют свою работу с использованием рекурсивного программирования или итеративного программирования, это их бизнес. –

12

dogs.Join (щенков,() => верно,() => верно, (один, два) => новый Кортеж (один, два));

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

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

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

+0

Большое спасибо. Вау, это сложно. Показывается, почему они изобрели синтаксис понимания запроса linq, он, безусловно, более читабельен, чем в таких случаях. – Chris

+0

@ Эрик Lippert не является пунктом SelectMany, чтобы свернуть несколько IEnumerable (из разных объектов одного типа) в один IEnumerable ? Просмотрев документацию, я не нахожу другого способа перевести ваш N-образный продукт в LINQ без синтаксиса запроса. Разве соединение не определено как ограниченный набор декартова продукта? Мне не хватает оператора? Является ли предложение from только эквивалентом предложения foreach или существует отдельный оператор? – McKay

+2

Это много вопросов. (1) не является точкой SelectMany, чтобы свернуть несколько IEnumerable в один IEnumerable ? Да, хотя, конечно, это больше, чем просто. С точки зрения «последовательности» SelectMany является декартовым оператором продукта с проекцией на задний конец. С более общей точки зрения «монада» SelectMany является операцией Bind на шаблоне монады. –

9

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

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

Я действительно хочу все возможные комбинации N наборов щенков, но спасибо за то, что поставил меня на правильный путь. – Chris

 Смежные вопросы

  • Нет связанных вопросов^_^