
一般情况下的递归解析树形参考:
https://www.tnblog.net/aojiancc2/article/details/4785
这个是sqlsugar封装的关于树形相关的方法
https://www.donet5.com/home/doc?masterId=1&typeId=2311
树形递归解析算法,处理特殊的根节点条件,特定的顶级顶层条件
在sqlsguar中有一个这样的表
public class Tree
{
[SqlSugar.SugarColumn(IsPrimaryKey = true)]
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public string Type { get; set; }
public List<Tree> Child { get; set; }
}
一般情况下顶级的都是ParentId=0或者是null,但是这里的情况有一点特殊,最顶层的数据是type=’校区’或者type = ‘一级部门’
应该怎么写递归算法处理这种结构的数据成一个树形结构呢。
最顶层的数据的 Type
属性值为 '校区'
或 '一级部门'
。以下是实现这个功能的代码示例:
首先,假设你已经从数据库中获取了所有的 Tree
对象并存储在一个列表中,比如 List<Tree> allTrees
。
接下来,你可以使用以下递归算法来构建树形结构:
using System;
using System.Collections.Generic;
using System.Linq;
public class Tree
{
[SqlSugar.SugarColumn(IsPrimaryKey = true)]
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public string Type { get; set; }
public List<Tree> Child { get; set; } = new List<Tree>();
}
public class TreeBuilder
{
public List<Tree> BuildTree(List<Tree> allTrees)
{
// 查找根节点,即 Type 为 '校区' 或 '一级部门' 的节点
var roots = allTrees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
// 创建一个字典,方便根据 Id 快速查找节点
var treeLookup = allTrees.ToDictionary(t => t.Id);
// 递归函数,构建树形结构
void BuildTreeRecursive(Tree parent)
{
foreach (var childId in allTrees
.Where(t => t.ParentId == parent.Id)
.Select(t => t.Id))
{
if (treeLookup.TryGetValue(childId, out var child))
{
parent.Child.Add(child);
BuildTreeRecursive(child);
}
}
}
// 对每个根节点调用递归函数
foreach (var root in roots)
{
BuildTreeRecursive(root);
}
return roots;
}
}
// 示例用法
public class Program
{
public static void Main()
{
// 假设这是从数据库中获取的所有 Tree 对象
List<Tree> allTrees = new List<Tree>
{
// 示例数据
new Tree { Id = 1, Name = "校区A", ParentId = 0, Type = "校区" },
new Tree { Id = 2, Name = "部门1", ParentId = 1, Type = "一级部门" },
new Tree { Id = 3, Name = "部门2", ParentId = 1, Type = "一级部门" },
new Tree { Id = 4, Name = "小组1", ParentId = 2, Type = "小组" },
new Tree { Id = 5, Name = "小组2", ParentId = 2, Type = "小组" },
// 添加更多数据...
};
TreeBuilder builder = new TreeBuilder();
List<Tree> treeStructure = builder.BuildTree(allTrees);
// 输出或处理 treeStructure
PrintTree(treeStructure, 0);
}
public static void PrintTree(List<Tree> trees, int indent)
{
foreach (var tree in trees)
{
Console.WriteLine($"{new string(' ', indent * 2)}{tree.Name} ({tree.Type})");
PrintTree(tree.Child, indent + 1);
}
}
}
代码解释
Tree 类:包含树节点的定义,包括
Id
,Name
,ParentId
,Type
, 和Child
列表。TreeBuilder 类:包含构建树形结构的
BuildTree
方法。BuildTree 方法:
- 首先,查找根节点,即
Type
为'校区'
或'一级部门'
的节点。 - 创建一个字典
treeLookup
,用于根据Id
快速查找节点。 - 定义递归函数
BuildTreeRecursive
,用于构建树形结构。 - 对每个根节点调用递归函数。
- 首先,查找根节点,即
PrintTree 方法:用于打印树形结构,便于验证结果。
示例用法:创建一些示例数据,并调用
BuildTree
方法构建树形结构,最后打印出来。
通过这种方式,你可以将平面表数据转换为树形结构,并处理特定的根节点条件。
树形获取顶级下面所有的子级id
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
public class Tree
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public string Type { get; set; }
public List<Tree> Child { get; set; } = new List<Tree>();
}
public class TreeHelper
{
public Dictionary<int, List<int>> GetAllSubDepartmentIds(List<Tree> trees)
{
// 字典来存储每个顶级部门ID及其所有子部门ID
Dictionary<int, List<int>> subDepartmentIdsByTopDepartment = new Dictionary<int, List<int>>();
// 找出所有顶级节点(没有父节点的节点)
var topDepartments = trees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
foreach (var topDepartment in topDepartments)
{
List<int> subIds = new List<int>();
// 递归收集当前顶级节点下的所有子节点ID
CollectSubDepartmentIds(topDepartment, subIds);
// 将结果添加到字典中
subDepartmentIdsByTopDepartment[topDepartment.Id] = subIds;
}
return subDepartmentIdsByTopDepartment;
}
private void CollectSubDepartmentIds(Tree node, List<int> subDepartmentIds)
{
// 添加当前节点的ID(通常顶级节点不应该在这里添加,但在递归中保持一致性)
// 注意:如果顶级节点的ID不应该出现在子节点列表中,则应该在此处进行条件判断
// 例如:if (node.ParentId != null) subDepartmentIds.Add(node.Id);
// 但由于我们是从顶级节点开始的,所以这里直接添加是安全的(对于子节点递归调用)
subDepartmentIds.Add(node.Id);
// 递归处理子节点
foreach (var child in node.Child)
{
CollectSubDepartmentIds(child, subDepartmentIds);
}
}
}
// 示例用法
public class Program
{
public static void Main()
{
// 假设这是从数据库中获取的所有Tree对象
List<Tree> trees = new List<Tree>
{
// ...(填充示例数据)
// 例如:
// new Tree { Id = 1, Name = "顶级部门1", ParentId = null, Type = "一级部门", Child = new List<Tree> { ... } },
// new Tree { Id = 2, Name = "顶级部门2", ParentId = null, Type = "一级部门", Child = new List<Tree> { ... } },
// ...
};
TreeHelper helper = new TreeHelper();
Dictionary<int, List<int>> allSubDepartmentIds = helper.GetAllSubDepartmentIds(trees);
// 输出每个顶级部门及其所有子部门的ID
foreach (var kvp in allSubDepartmentIds)
{
Console.WriteLine($"顶级部门ID: {kvp.Key}, 子部门ID: {string.Join(", ", kvp.Value)}");
}
}
}
和树形结构表,关联的用户表,两个表一起解析出来数据
现在还有一个表,表结构如下:
public class VAccountDepartment
{
public string AccountID { get; set; }
public string Name { get; set; }
public int? DepartID { get; set; }
}
这里边的DepartID就是Tree里边的Id,每个tree里边的id都可能有这个数据,选中想把tree的子级也包含进行这块用户的数据。
为了将 VAccountDepartment
表与 Tree
表关联起来,并构建一个包含这些关联信息的树形结构,你需要对之前的逻辑进行一些调整。这里的关键是,你需要根据 VAccountDepartment
表中的 DepartID
来找到对应的 Tree
节点,并将 VAccountDepartment
实例附加到这些节点上。
以下是一个可能的实现方式:
- 首先,从数据库中获取
Tree
和VAccountDepartment
的所有数据。 - 构建
Tree
的树形结构,如之前所示。 - 遍历
VAccountDepartment
列表,将每个实例附加到对应的Tree
节点上。
这里是一个修改后的代码示例:
using System;
using System.Collections.Generic;
using System.Linq;
public class Tree
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public string Type { get; set; }
public List<Tree> Child { get; set; } = new List<Tree>();
public List<VAccountDepartment> Departments { get; set; } = new List<VAccountDepartment>();
}
public class VAccountDepartment
{
public string AccountID { get; set; }
public string Name { get; set; }
public int? DepartID { get; set; }
}
public class TreeBuilder
{
public List<Tree> BuildTreeWithDepartments(List<Tree> allTrees, List<VAccountDepartment> allDepartments)
{
// 构建树形结构
var roots = BuildTree(allTrees);
// 创建一个字典,方便根据 Id 快速查找树节点
var treeLookup = roots.SelectMany(r => GetAllDescendants(r)).ToDictionary(t => t.Id);
// 将 VAccountDepartment 实例附加到对应的 Tree 节点上
foreach (var dept in allDepartments)
{
if (dept.DepartID.HasValue && treeLookup.TryGetValue(dept.DepartID.Value, out var treeNode))
{
treeNode.Departments.Add(dept);
}
// 如果需要处理 DepartID 为 null 的情况,可以在这里添加逻辑
}
return roots;
}
private List<Tree> BuildTree(List<Tree> allTrees)
{
// 查找根节点
var roots = allTrees.Where(t => t.Type == "校区" || t.Type == "一级部门").ToList();
// 递归函数,构建树形结构
void BuildTreeRecursive(Tree parent)
{
foreach (var child in allTrees.Where(t => t.ParentId == parent.Id))
{
parent.Child.Add(child);
BuildTreeRecursive(child);
}
}
// 对每个根节点调用递归函数
foreach (var root in roots)
{
BuildTreeRecursive(root);
}
return roots;
}
private IEnumerable<Tree> GetAllDescendants(Tree node)
{
return new[] { node }.Concat(node.Child.SelectMany(GetAllDescendants));
}
}
// 示例用法
public class Program
{
public static void Main()
{
// 假设这是从数据库中获取的所有 Tree 对象
List<Tree> allTrees = new List<Tree>
{
// ...(示例数据)
};
// 假设这是从数据库中获取的所有 VAccountDepartment 对象
List<VAccountDepartment> allDepartments = new List<VAccountDepartment>
{
// ...(示例数据)
};
TreeBuilder builder = new TreeBuilder();
List<Tree> treeStructureWithDepartments = builder.BuildTreeWithDepartments(allTrees, allDepartments);
// 输出或处理 treeStructureWithDepartments
// ...
}
}
在这个示例中,BuildTreeWithDepartments
方法首先调用 BuildTree
来构建树形结构,然后创建一个字典 treeLookup
来存储所有树节点,以便快速查找。接下来,它遍历 allDepartments
列表,并将每个 VAccountDepartment
实例附加到对应的 Tree
节点上。GetAllDescendants
方法是一个辅助方法,用于递归地获取树的所有后代节点。
请注意,这个实现假设 DepartID
在 VAccountDepartment
表中是唯一的,并且每个 DepartID
都对应一个 Tree
节点。如果这不是情况,你可能需要添加一些额外的逻辑来处理重复或缺失的 DepartID
值。
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

