我有一个现有的课程:
public class Product
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Info { get; set; }
}
我也有一个给定的List<Product>
:
var Lst = new List<Product>();
Lst.Add(new Product{ Id=1,ParentId=0,Info="a"});
Lst.Add(new Product{ Id=2,ParentId=0,Info="a"});
Lst.Add(new Product{ Id=3,ParentId=0,Info="a"});
Lst.Add(new Product{ Id=60,ParentId=1,Info="a"});
Lst.Add(new Product{ Id=61,ParentId=1,Info="a"});
Lst.Add(new Product{ Id=62,ParentId=61,Info="a"});
Lst.Add(new Product{ Id=72,ParentId=61,Info="a"});
Lst.Add(new Product{ Id=90,ParentId=2,Info="a"});
可视化:
1
|
+---60
|
+---61
|
+---62
|
+---72
2
|
+---90
3
如您所见,List<>
flat 。 (所有项目都在列表中的同一级别。它只是id,parentId
代表层次结构)
现在 - 我需要创建结构List<>
,以便List
中的每个项目 in 其父对象:
所以我创建了一个额外的结构类来保存这个结构:
public class Node
{
public Product Product { get; set; }
public List<Node> LstNodes { get; set; }
}
现在我可以做到:
List<Node> lstNodes = new List<Node>();
最初我可以添加根源:
lstNodes=Lst.Where(product=>product.ParentId==0).Select(node=>new Node{Product=node}).ToList();
现在我可以开始递归,与父母一起插入项目。
那么问题在哪里?
问题:
我想首先避免插入根元素(root是ParentId=0
)。
使用一个递归方法(包括根)有没有办法做到这一点?
期望的结果:lstNodes
中的3个节点,其中每个节点递归地具有其子节点。
答案 0 :(得分:4)
这样的东西?
List<Node> GetNodes(List<Product> lst, int parentId = 0)
{
var childProducts = lst.Where(x=>x.ParentId == parentId);
return childProducts
.Select(x=> new Node { Product = x, LstNodes = GetNodes(lst, x.Id)}
.ToList();
}
纯粹的通用版本:
class Node<T>
{
public T Item { get; set; }
public List<Node<T>> LstNodes { get; set; }
}
List<Node<T>> GetNodes<T>(List<T> lst, Func<T, int> idSelector, Func<T, int> parentIdSelector, int parentId = 0)
{
var childProducts = lst.Where(x=>parentIdSelector(x) == parentId);
return childProducts
.Select(x=> new Node<T> { Item = x, LstNodes = GetNodes<T>(lst, idSelector,parentIdSelector, idSelector(x))})
.ToList();
}
GetNodes(Lst,x=>x.Id,x=>x.ParentId, 0);
答案 1 :(得分:1)
你可以试试这个:
static List<Node> BuildTree(List<Product> lst, int topID)
{
var tree = Enumerable.Empty<Node>().ToList();
if (lst == null)
{
return tree;
}
foreach (var product in lst)
{
if (product.ParentId == topID)
{
Node node = new Node
{
Product = product,
LstNodes = BuildTree(lst.Where(p => p.ParentId == product.Id).ToList(), product.Id)
};
tree.Add(node);
}
}
return tree;
}
您可以致电:List<Node> roots = BuildTree(Lst, 0);
答案 2 :(得分:1)
到目前为止提出的解决方案有效,但每个节点迭代整个集合一次 这使得它们O(n2)并且不适合大型集合(数据库,......) 这是一个以线性时间运行的解决方案:
var products = new List<Product>();
products.Add(...);
...
var nodes = products.Select(p => new Node { Product = p }).ToList(); // 1
var nodeWithId = nodes.ToDictionary(n => n.Product.Id); // 2
var parentChildren = nodes.Where(n => n.Product.ParentId != 0)
.ToLookup(n => nodeWithId[n.Product.ParentId]); // 3
foreach (var pc in parentChildren) // 4
{
var parent = pc.Key;
var children = pc.ToList();
parent.LstNodes = children;
}
说明: