【问题标题】:Inverting a Hierarchy with Linq使用 Linq 反转层次结构
【发布时间】:2015-02-18 04:51:03
【问题描述】:

给定班级

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

List<Article> articles;

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

Dictionary<string, List<Article>> articlesPerTag;

我知道我可以像这样选择所有标签

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

但是,我不确定如何将每个选定的标签关联回它所来自的文章。

我知道我可以按照传统的方式写这个

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 完成此操作。

【问题讨论】:

    标签: c# linq linq-to-objects


    【解决方案1】:

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

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

    【讨论】:

    • 我脑海中的缺失部分是选择new {t, a} 而不是a.Tags。谢谢。
    【解决方案2】:

    使用 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()));
    

    【讨论】:

    • 这不会产生Dictionary&lt;string, Article&gt;
    • 完成。现在它应该提供一个 Dictionary>.
    • 我通过在 ToDictionary() 调用中选择结果来简化查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多