在 C# 中使用 LINQ 查找分组列表的组合

本文关键字:列表 组合 查找 LINQ | 更新日期: 2023-09-27 18:35:43

假设我有一个对象,其中包含一个人的名字和他们的原籍城市。

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 的优雅方法可以做到这一点,任何人都可以提供一些信息吗?

在 C# 中使用 LINQ 查找分组列表的组合

我们将从以下从这里逐字获取的代码片段开始。 (这是一个很好的链接,值得一读)。

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