web-dev-qa-db-fra.com

Existe-t-il un bon moyen LINQ de faire un produit cartésien?

J'ai une structure de classe comme ça:

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

Il y a une personne. Il a 1..n chiens. Chaque chien a 1..n chiots.

Je veux une liste de toutes les combinaisons possibles de chiots, en prenant 1 chiot de chaque chien. Par exemple:

chien 1 chiot A, chien 2 chiot A chien 1 chiot A, chien 2 chiot B chien 1 chiot B, chien 2 chiot A chien 1 chiot B, chien 2 chiot B

Si c'était dans des tables sql, je ferais quelque chose comme ceci pour 'multiplier' les tables:

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

Existe-t-il un moyen linq-ish de faire ce genre de chose ???

Merci beaucoup

56
Chris

Si je comprends la question, vous voulez le produit cartésien de n ensembles de chiots.

Il est facile d'obtenir le produit cartésien si vous savez au moment de la compilation combien d'ensembles il y a:

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

Supposons que dog1 a des chiots p11, p12, dog2 a un chiot p21 et dog3 a des chiots p31, p32. Cela vous donne

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

Où chaque ligne est un type anonyme. Si vous ne savez pas au moment de la compilation combien d'ensembles il y a, vous pouvez le faire avec un peu plus de travail. Voir mon article sur le sujet:

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

et cette question StackOverflow:

Génération de toutes les combinaisons possibles

Une fois que vous avez la méthode CartesianProduct<T> alors tu peux dire

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

obtenir

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

Où chaque rangée est une séquence de chiots.

Ça a du sens?

83
Eric Lippert

dogs.Join (chiots, () => vrai, () => vrai, (un, deux) => nouveau Tuple (un, deux));

Vous pouvez effectuer une jointure régulière, mais les sélecteurs renvoient tous les deux la même valeur, car je veux que toutes les combinaisons soient valides. Lors de la combinaison, mettez les deux dans un Tuple (ou une structure de données différente de votre choix).

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

Cela devrait faire un produit cartésien.

18
McKay

Si vous voulez toutes les combinaisons possibles de chien et de chiot, vous feriez une jointure croisée:

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