2012-05-30 44 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