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

C#如何基于非规范化记录最优实现树形菜单,避免LINQ递归写法

需求说明

需要基于非规范化的体育赛事记录生成三级树形菜单,原始记录为SPORT(运动项目)、LEAGUE(联赛)、MATCH(赛事)的扁平结构,样例数据如下:

SPORTLEAGUEMATCH
Sport1League1Match1
Sport1League1Match2
Sport1League2Match1
Sport2League1Match1
现有实现痛点

当前采用多层嵌套LINQ GroupBy的写法,层级固定扩展性差,调整菜单层级需要修改嵌套结构,现有代码如下(原有代码存在MenuItem构造函数未给SubMenuItems赋值的bug,生成的节点子菜单会为空):

// 现有嵌套GroupBy实现
sportMenu.GroupBy(x => x.Sport)
         .Select(x => MenuItem.Create(x.Key, 
                      x.GroupBy(x => x.League)
                      .Select(x => MenuItem.Create(x.Key, x.GroupBy(x => x.Match)
                                                           .Select( x =>MenuItem.Create(x.Key, new List<MenuItem>()))))
                      .ToList()));

// MenuItem定义
public class MenuItem
{
    public string Name { get; set; }
    public List<MenuItem> SubMenuItems { get; set; }
    
    public static MenuItem Create(string name, List<MenuItem> subMenuItems)
    {
        return new MenuItem(name.Trim(), subMenuItems);
    }
    private MenuItem(string name, List<MenuItem> subMenuItems)
    {
        Name = name;
        SubMenuItems = subMenuItems;
    }
}
优化实现(无嵌套GroupBy)

采用逐行遍历+字典缓存节点的写法,层级逻辑清晰,后续新增/减少菜单层级只需调整遍历逻辑即可,无需嵌套代码:

// 原始记录实体类定义
public class SportRecord
{
    public string Sport { get; set; }
    public string League { get; set; }
    public string Match { get; set; }
}

// 菜单生成方法
public List<MenuItem> BuildSportMenu(List<SportRecord> records)
{
    // 缓存已创建的运动项目节点
    var sportDict = new Dictionary<string, MenuItem>();
    // 缓存已创建的联赛节点,key格式为 运动项目名_联赛名 避免重名冲突
    var leagueDict = new Dictionary<string, MenuItem>();
    var rootMenu = new List<MenuItem>();

    foreach (var record in records)
    {
        // 处理第一级:运动项目节点
        if (!sportDict.TryGetValue(record.Sport, out var sportNode))
        {
            sportNode = MenuItem.Create(record.Sport, new List<MenuItem>());
            sportDict.Add(record.Sport, sportNode);
            rootMenu.Add(sportNode);
        }

        // 处理第二级:联赛节点
        var leagueKey = $"{record.Sport}_{record.League}";
        if (!leagueDict.TryGetValue(leagueKey, out var leagueNode))
        {
            leagueNode = MenuItem.Create(record.League, new List<MenuItem>());
            leagueDict.Add(leagueKey, leagueNode);
            sportNode.SubMenuItems.Add(leagueNode);
        }

        // 处理第三级:赛事节点
        var matchNode = MenuItem.Create(record.Match, new List<MenuItem>());
        leagueNode.SubMenuItems.Add(matchNode);
    }

    return rootMenu;
}
  • 该实现时间复杂度为O(n),仅需遍历一次原始记录,性能优于嵌套GroupBy的O(n*层级数)
  • 如需新增第四级节点(比如赛事阶段),只需新增对应层级的字典缓存,在循环内补充对应逻辑即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 02:42:02