首页 新闻 会员 周边 捐助

如何用 C# 将 List 转换为 Tree 数据结构

0
悬赏园豆:30 [已解决问题] 解决于 2025-06-22 08:35

这是在重构园子博客后台多级目录的实现代码时遇到的一个问题,请问如何将从数据库中获取的分类列表转换为树形数据结构?

dudu的主页 dudu | 高人七级 | 园豆:24728
提问于:2025-06-21 19:01
< >
分享
最佳答案
0

deepseek 给出的实现代码

sing System;
using System.Collections.Generic;
using System.Linq;

public class TreeNode<T>
{
    public T Data { get; set; }
    public List<TreeNode<T>> Children { get; set; } = new List<TreeNode<T>>();
}

public static class TreeBuilder
{
    public static List<TreeNode<T>> BuildTree<T, TKey>(
        List<T> items,
        Func<T, TKey> idSelector,
        Func<T, TKey> parentIdSelector,
        IEqualityComparer<TKey> comparer = null)
    {
        if (items == null || idSelector == null || parentIdSelector == null)
            throw new ArgumentNullException("Arguments cannot be null.");
        
        comparer = comparer ?? EqualityComparer<TKey>.Default;
        
        // Create all nodes upfront
        var nodeLookup = items.ToDictionary(idSelector, item => new TreeNode<T> { Data = item }, comparer);
        var roots = new List<TreeNode<T>>();
        
        foreach (var item in items)
        {
            TKey id = idSelector(item);
            TKey parentId = parentIdSelector(item);
            var node = nodeLookup[id];
            
            // Handle root items: parentId is default, self-referencing, or missing parent
            if (parentId == null || 
                parentId.Equals(default(TKey)) || 
                comparer.Equals(parentId, id) || 
                !nodeLookup.TryGetValue(parentId, out var parent))
            {
                roots.Add(node);
            }
            else
            {
                parent.Children.Add(node);
            }
        }
        
        return roots;
    }
}
dudu | 高人七级 |园豆:24728 | 2025-06-21 21:11

改进后的实现

TreeNode.cs

[JsonDerivedType(typeof(BlogCategory), nameof(BlogCategory))]
public class TreeNode<T>
{
    public List<TreeNode<T>> Children { get; set; } = [];
}

BlogCategory.cs

public class BlogCategory : TreeNode<BlogCategory>
{
    public int CategoryId { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
}

TreeBuilder.cs

public static class TreeBuilder
{ 
    public static List<T> BuildTree<T, TKey>(
        List<T> items,
        Func<T, TKey> idSelector,
        Func<T, TKey> parentIdSelector,
        IEqualityComparer<TKey> comparer = null)
        where T : TreeNode<T>
    {
        ArgumentNullException.ThrowIfNull(items);
        ArgumentNullException.ThrowIfNull(idSelector);
        ArgumentNullException.ThrowIfNull(parentIdSelector);

        comparer = comparer ?? EqualityComparer<TKey>.Default;

        // Create all nodes upfront
        var nodeLookup = items.ToDictionary(idSelector, item => item, comparer);
        var roots = new List<T>();

        foreach (var item in items)
        {
            TKey id = idSelector(item);
            TKey parentId = parentIdSelector(item);
            var node = nodeLookup[id];

            // Handle root items: parentId is default, self-referencing, or missing parent
            if (parentId == null ||
                parentId.Equals(default(TKey)) ||
                comparer.Equals(parentId, id) ||
                !nodeLookup.TryGetValue(parentId, out var parent))
            {
                roots.Add(node);
            }
            else
            {
                parent.Children.Add(node);
            }
        }

        return roots;
    }
}

Program.cs

var json = File.ReadAllText("categories.json");
var categories = JsonSerializer.Deserialize<BlogCategory[]>(json)!.ToList();

var rootNodes = TreeBuilder.BuildTree(
    categories!,
    idSelector: item => item.CategoryId,
    parentIdSelector: item => item.ParentId
);

File.WriteAllText("out.json", JsonSerializer.Serialize(rootNodes));
dudu | 园豆:24728 (高人七级) | 2025-06-21 22:04
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册