2012-05-30 81 views
5

可以說我有一個包含人名和他們的原籍城市的對象。在c中使用LINQ查找分組列表的組合#

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

而且我有一個列表,並添加了以下條目。

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

我在找的是所有可能的名稱組合,按城市分組。

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

我能做到這一點,如果我事先知道的組數,通過使用下面的代碼

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); 
    }   
} 

但是,這隻能如果我知道團體提前數,並迅速隨着團體數量的增長變得笨重。我敢肯定,有一種使用LINQ來完成這項工作的優雅方式,任何人都可以從中得到一些啓示。

+0

看看這個答案http://stackoverflow.com/questions/9168269/permutation-algorithms-in-c-sharp。你可以加入你自己的清單。 – Brad

+0

@Brad這對於2個城市列出的示例有效。 OP想要的是一個N維交叉乘積,其中N直到運行時才知道。該代碼片段不提供它。 – Servy

回答

3

我們將從以下代碼段開始,從here開始使用verbatum。 (這是一個很好的鏈接,值得一讀)。

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 })); 
    } 
} 

之後,所有我們需要做的是:

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

好的,輸入您提供的數據後進行測試,並打印預期結果。 – Servy

+0

奇妙的是,這很好。還有一個非常有趣的啓動鏈接,非常感謝。 – John