使用 Linq 反转层次结构

Inverting a Hierarchy with Linq

鉴于 class

public class Article
{
    public string Title { get; set; }
    public List<string> Tags { get; set; }
}

List<Article> articles;

如何使用 Linq 从单个标签(可能与 1 篇或多篇文章相关联)创建 "map"?

Dictionary<string, List<Article>> articlesPerTag;

我知道我可以select所有这样的标签

var allTags = articlesPerTag.SelectMany(a => a.Tags);

但是,我不确定如何将每个 selected 标签关联回其来源的文章。

我知道我可以按照

的方式写这个
Dictionary<string, List<Article>> map = new Dictionary<string, List<Article>>();
foreach (var a in articles)
{
    foreach (var t in a.Tags)
    {
        List<Article> articlesForTag;
        bool found = map.TryGetValue(t, out articlesForTag);
        if (found)
            articlesForTag.Add(a);
        else
            map.Add(t, new List<Article>() { a });
    }
}

但我想了解如何使用 Linq 完成此操作。

还有一种使用 GroupBy 的方法。虽然有点复杂。

articles.SelectMany(article => article.Tags)
        .Distinct()
        .GroupBy(tag => tag, tag => articles.Where(a => a.Tags.Contains(tag)))
        .ToDictionary(group => group.Key, 
                      group => group.ToList().Aggregate((x, y) => x.Concat(y).Distinct()));

如果您特别需要它作为从标签到文章的字典,您可以使用类似这样的东西。

var map = articles.SelectMany(a => a.Tags.Select(t => new { t, a }))
    .GroupBy(x => x.t, x => x.a)
    .ToDictionary(g => g.Key, g => g.ToList());

虽然使用查找会更有效,但这正是您要构建的内容。

var lookup = articles.SelectMany(a => a.Tags.Select(t => new { t, a }))
    .ToLookup(x => x.t, x => x.a);