LinQ C# - 根据List <string>属性</string>中包含的字符串对对象列表进行分组

时间:2014-05-30 10:08:32

标签: c# linq list collections group-by

我在字符串列表上进行分组时遇到问题。

我的课程&#34; Post&#34;包含名为Tags:

的List属性
public class Post
{
    public string Title { get; set; }
    public int Position { get; set; }
    public List<string> Tags { get; set; }
}

我的代码中的其他地方我正在收集列表中的所有帖子。现在,其中许多帖子彼此共享标签。假设:

Post_1.Tags = new List<string>(){"a", "b", "c"};
Post_2.Tags = new List<string>(){"a", "d", "e"};
Post_3.Tags = new List<string>(){"b", "c", "d"};
Post_4.Tags = new List<string>(){"c", "d", "f"};

我正在尝试使用这种结构获得一个集合:

Key: a; Values: Post_1, Post_2;
Key: b; Values: Post_1, Post_3;
Key: c; Values: Post_1, Post_3, Post_4;
Key: d; Values: Post_2, Post_3, Post_4;
Key: e; Values: Post_2;
Key: f; Values: Post_4;

我想我需要使用GroupBy(),但我仍然坚持使用语法,因为:

List<Post> Posts = // all my posts
ILookup<string, Post> ByTag = Posts.GroupBy(p => p.Tags) ...

显然是针对标记列表而不是单个标记。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

var tags = Posts.SelectMany(p => p.Tags).Distinct();
var groups = from p in Posts
    from t in tags.Where(tag => p.Tags.Contains(tag))
    group p by t
    into gr
    select gr;

<强>解释 SelectMany.Distinct - 使IEnumerable,包含所有帖子中没有重复的所有标签。 前2个 - 加入标签和帖子。加入条件 - 帖子应包含标签。最终的收集将是每一个可能的帖子和它的标签。 Group会以某种方式对这些对进行分组,gr的键将是一个标记,gr将是所有带有该标记的帖子的集合。我习惯了字典并编写了一段代码,以后可以通过调用Dictionary<string, List<Post>>将其转换为ToDictionary(g => g.Key, g => g.ToList())。如果您想要查找,则不需要组部分:

var tags = Posts.SelectMany(p => p.Tags).Distinct();
var postAndTagPairs = from p in Posts
    from t in tags.Where(tag => p.Tags.Contains(tag))
    select new {t, p};
var lookup = postAndTagPairs.ToLookup(pat => pat.t, pat => pat.p);

答案 1 :(得分:0)

首先需要获得一个独特的标签列表。假设帖子在这样的列表中:

var posts = new List<Post>
{
    new Post { Tags = new List<string>(){"a", "b", "c"} },
    new Post { Tags = new List<string>(){"a", "d", "e"} },
    new Post { Tags = new List<string>(){"b", "c", "d"} },
    new Post { Tags = new List<string>(){"c", "d", "f"} }
};

你得到这样的标签:

var allTags = posts.SelectMany(p => p.Tags).Distinct();

然后你可以进行分组:

var result = from p in posts
             from t in allTags.Where(t => p.Tags.Contains(t))
             group p by t into grp
             select grp;