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;
}
}
改进后的实现
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));