如何实现Permission集合的嵌套GroupBy分组处理
问题描述
我有如下C# DTO和示例数据:
class Permission { public string ObjectId { get; set; } public string ObjectType { get; set; } public string Scope { get; set; } public string? AccountId { get; set; } public string? GroupId { get; set; } } var permissions = new List<Permission>() { new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "2", GroupId = null }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = null, GroupId = "1" }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:write", AccountId = "2", GroupId = null }, new(){ ObjectId = "2", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null }, };
期望得到如下JSON结构:
{ "1": { "read": { "accounts": ["1", "2"], "groups": ["1"] }, "write": { "accounts": ["2"], "groups": [] } }, "2": { "read": { "accounts": ["1"], "groups": [] } } }
本质需求是:将Permission数组先按ObjectId分组,再按Scope中的操作类型(如read、write)分组,每个操作类型下收集对应的非空AccountId和GroupId数组。我尝试用GroupBy得到了IGrouping类型,但不知道后续如何转换为目标结构。
解决方案
可以通过嵌套GroupBy + 字典转换来实现需求,具体代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; class Permission { public string ObjectId { get; set; } public string ObjectType { get; set; } public string Scope { get; set; } public string? AccountId { get; set; } public string? GroupId { get; set; } } class Program { static void Main() { var permissions = new List<Permission>() { new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = "2", GroupId = null }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:read", AccountId = null, GroupId = "1" }, new(){ ObjectId = "1", ObjectType = "link", Scope = "link:write", AccountId = "2", GroupId = null }, new(){ ObjectId = "2", ObjectType = "link", Scope = "link:read", AccountId = "1", GroupId = null }, }; var result = permissions // 第一步:按ObjectId分组 .GroupBy(p => p.ObjectId) // 转换为ObjectId为键的字典 .ToDictionary( objGroup => objGroup.Key, objGroup => objGroup // 第二步:按Scope中的操作类型分组(从link:read提取read) .GroupBy(p => p.Scope.Split(':')[1]) // 转换为操作类型为键的字典 .ToDictionary( scopeGroup => scopeGroup.Key, scopeGroup => new { // 收集非空的AccountId,去重后转列表 accounts = scopeGroup.Where(p => p.AccountId != null) .Select(p => p.AccountId!) .Distinct() .ToList(), // 收集非空的GroupId,去重后转列表 groups = scopeGroup.Where(p => p.GroupId != null) .Select(p => p.GroupId!) .Distinct() .ToList() } ) ); // 序列化为格式化后的JSON var json = JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true }); Console.WriteLine(json); } }
关键步骤说明:
- 第一层分组:用
GroupBy(p => p.ObjectId)把所有权限按对象ID归类,得到每个对象对应的权限集合。 - 转换为顶层字典:用
ToDictionary把分组结果转为以ObjectId为键的字典,方便后续序列化。 - 第二层分组:对每个对象的权限集合,通过
Scope.Split(':')[1]提取操作类型(如read、write),再按该类型分组。 - 收集账号与组ID:在每个操作类型组内,筛选出非空的
AccountId和GroupId,用Distinct()避免重复条目,最后转为列表。 - 序列化JSON:用
System.Text.Json(或Newtonsoft.Json)把最终字典序列化为格式化的JSON字符串。
注意事项:
- 如果
Scope的格式不是[前缀]:[操作类型],需要调整提取操作类型的逻辑(比如正则匹配)。 - 示例中期望结果的
groups包含["1","2","3"],但原始数据只有GroupId="1"的条目,实际运行会得到groups=["1"],若需要额外数据,需补充对应的Permission对象。
内容的提问来源于stack exchange,提问作者user17365408
相关产品推荐
相关产品推荐

