繁体   English   中英

LINQ:按列表字段分组

[英]LINQ: group by a field that is a list

我有一个 Publication 对象列表:

public class Publication 
{
    public List<string> Authors { get; set; }
}

我想使用 LINQ 按作者对我的发布对象进行分组。 我的解决方案使用字典,如下所示:

var dict = new Dictionary<string, List<Publication>>();

foreach (var publication in list)
{
    foreach(var author in publication.Authors)
    {
        if (dict.ContainsKey(author))
        {
            dict[author].Add(publication);
        }
        else
        {
            dict.Add(author, new List<Publication> { publication });
        }
    }
}

然而,这对我来说似乎很丑陋。 这个问题一定有一个简单而优雅的单线,但我无法直截了当。 我还尝试在 Authors 属性上使用 selectmany 将列表展平,然后将它们分组,但它只去除了作者字符串,并且发布对象消失了。

使用 LINQ,您可以这样做:

var groupedByAuthor = list
    .SelectMany(publication => 
        publication.Authors.Select(author => new { author, publication }))
    .GroupBy(arg => arg.author, keyValue => keyValue.publication)
    .ToArray();

但这会慢一点。

您可以使用 Linq 和一些匿名类:

public class Publication
{
    public List<string> Authors { get; set; }

    public string Title { get; set; }
}

class Program
{
    static void Main()
    {
        IEnumerable<Publication> publications; // YOUR DATA HERE!

        var groupsByAuthor = publications.SelectMany(publication => publication.Authors.Select(author => new { Publication = publication, Author = author })).GroupBy(x => x.Author);

        foreach (var gba in groupsByAuthor)
        {
            Console.WriteLine(gba.Key);
            foreach (var pub in gba)
            {
                Console.WriteLine(pub.Publication.Title);
            }
        }

        Console.ReadLine();
    }
}

如果您更关心干净和富有表现力的代码,您可能想尝试创建一个扩展方法,而不是强制执行丑陋的 linq 查询。 代码应如下所示。

class Program
{
    static void Main(string[] args)
    {
        List<Publication> test = new List<Publication>();
        Dictionary<string, List<Publication>> publicationsByAuther = test.GroupByAuthor();
    }
}


public static class Extensions
{

    public static Dictionary<string, List<Publication>> GroupByAuther(this List<Publication> publications)
    {
        Dictionary<string, List<Publication>> dict = new Dictionary<string, List<Publication>>();
        foreach (var publication in publications)
        {
            foreach (var author in publication.Authors)
            {
                if (dict.ContainsKey(author))
                {
                    dict[author].Add(publication);
                }
                else
                {
                    dict.Add(author, new List<Publication>
                {
                    publication
                });
                }
            }
        }
        return dict;
    }
}

您可能会考虑将添加新作者与添加出版物的情况分开。 把代码变成这样:

var dict = new Dictionary<string, List<Publication>>();
foreach (var publication in list)
{
    foreach (var author in publication.Authors)
    {
        if (!dict.ContainsKey(author))
            dict.Add(author, new List<Publication>());
        dict[author].Add(publication);
    }
}

它不是 LINQ 也不是一个新的解决方案,但也许它有助于优雅

你也可以这样做:

var dict = pubs.SelectMany(p => p.Authors)
               .ToDictionary(
                   a => a, 
                   a => pubs.Where(p => p.Contains(a)).ToList())
               );

没有经过测试,但你明白了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM