You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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);
    }
}

关键步骤说明:

  1. 第一层分组:用GroupBy(p => p.ObjectId)把所有权限按对象ID归类,得到每个对象对应的权限集合。
  2. 转换为顶层字典:用ToDictionary把分组结果转为以ObjectId为键的字典,方便后续序列化。
  3. 第二层分组:对每个对象的权限集合,通过Scope.Split(':')[1]提取操作类型(如read、write),再按该类型分组。
  4. 收集账号与组ID:在每个操作类型组内,筛选出非空的AccountId和GroupId,用Distinct()避免重复条目,最后转为列表。
  5. 序列化JSON:用System.Text.Json(或Newtonsoft.Json)把最终字典序列化为格式化的JSON字符串。

注意事项:

  • 如果Scope的格式不是[前缀]:[操作类型],需要调整提取操作类型的逻辑(比如正则匹配)。
  • 示例中期望结果的groups包含["1","2","3"],但原始数据只有GroupId="1"的条目,实际运行会得到groups=["1"],若需要额外数据,需补充对应的Permission对象。

内容的提问来源于stack exchange,提问作者user17365408

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 12:35:26