2012-05-30 16 views
5

Diciamo che ho un oggetto che contiene il nome di una persona e la loro città di origine.Ricerca di combinazioni di un elenco raggruppato utilizzando LINQ in C#

public class personDetails 
{ 
    public string City; 
    public string Name; 
} 

E ho un elenco con le seguenti voci aggiunto.

Name City 
John | London 
Jane | London 
Tom | New York 
Bob | New York 
Fred | New York 

Quello che sto cercando sono tutte le combinazioni possibili di nomi, raggruppati per città.

John Tom 
John Bob 
John Fred 
Jane Tom 
Jane Bob 
Jane Fred 

posso fare questo se so in anticipo il numero di gruppi, utilizzando il seguente codice

List<personDetails> personList = new List<personDetails>(); 
//populate list 

var groupedPersons = personList.GroupBy(c => c.City); 
foreach (var item1 in groupedPersons[0]) 
{ 
    foreach (var item2 in groupedPersons[1]) 
    { 
     Console.WriteLine(item1.Name + " " + item2.Name); 
    }   
} 

Tuttavia, questo funziona solo se so che il numero di gruppi in anticipo, e in fretta diventa ingombrante quando la quantità di gruppi aumenta. Sono certo che c'è un modo elegante per farlo usando LINQ, qualcuno può far luce?

+0

Date un'occhiata a questa risposta http://stackoverflow.com/questions/9168269/permutation-algorithms-in-c-sharp. Potresti unirti alla tua lista con se stessa. – Brad

+0

@Brad Funzionerebbe per l'esempio elencato con 2 città. Ciò che l'OP vuole è un prodotto incrociato a N dimensioni, in cui N non è noto fino al runtime. Questo snippet di codice non lo fornisce. – Servy

risposta

3

Inizieremo con il seguente snippet di codice estratto da here. (È un buon collegamento, vale la pena leggere).

public static class MyExtensions 
{ 
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) 
    { 
     IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() }; 
     return sequences.Aggregate(
      emptyProduct, 
      (accumulator, sequence) => 
      from accseq in accumulator 
      from item in sequence 
      select accseq.Concat(new[] { item })); 
    } 
} 

Dopo che tutto quello che dobbiamo fare è:

var groupedPersons = personList.GroupBy(c => c.City) 
    //need an enumerable of enumerables, not an enumerable of groupings, 
    //because the method isn't covariant. 
    .Select(group => group.AsEnumerable()); 

var results = groupedPersons.CartesianProduct(); 
foreach (var group in results) 
{ 
    foreach (var person in group) 
    { 
     Console.Write(person.Name + " "); 
    } 
    System.Console.WriteLine(); 
} 
+0

Ok, testalo dopo aver inserito i dati che hai fornito e stampa i risultati attesi. – Servy

+0

Fantastico, funziona benissimo. E un link molto interessante per l'avvio, molte grazie. – John

Problemi correlati