从项目列表构建树

本文关键字:构建 列表 项目 | 更新日期: 2023-09-27 18:36:15

我想得到一些关于如何以有效的方式从项目列表中构建树的建议

 public class Item
    {
        public Item(int id, int? parentId)
        {
            Id = id;
            ParentId = parentId;
        }
        public int Id { get; private set; }
        public int? ParentId { get; private set; }
        public List<Item> SubItems  { get; set; }
    }
    private Item BuildATree()
    {
        var items = new List<Item>()
                        {
                            new Item(1, null),
                            new Item(2, 1),
                            new Item(3, 1),
                            new Item(4, 1),
                            new Item(5, 2),
                            new Item(6, 2),
                            new Item(7, 4),
                            new Item(8, 7),
                            new Item(9, 1),
                        };
        //Build a tree out of list items
    }

我期望的结果是每个项目都在其父项的子项列表中

不一定使用相同的 Item 类,因为 Id 将是多余的

从项目列表构建树

我会使用 LINQ:

//Build a tree out of list items
foreach (Item item in items)
{
    item.SubItems = items.Where(i => i.ParentId.Value == item.Id).ToList();
}

上级:

为了简化将项目从一个父项移动到另一个项的过程,您需要在每个项中存储对父项的引用。像这样:

public class Item
{
    public Item(int id, int? parentId)
    {
        Id = id;
        ParentId = parentId;
    }
    public int Id { get; private set; }
    public int? ParentId { get; private set; }
    public List<Item> SubItems  { get; set; }
    private Item _parent;
    public Item Parent 
    {
        get { return _parent; }
        set
        {
            if (_parent != null)
                _parent.SubItems.Remove(this);
            _parent = value;
            if (_parent != null)
                _parent.SubItems.Add(this);
        }
    }
}

如果以这种方式实现,则只需通过此属性设置新的父项就足以修改旧父项和新父项的子项集合 - 但请注意,您还需要更复杂的列表初始化机制。

足够高效的解决方案

private void RecursiveBuilder(ref Item i, IEnumerable<Item> li)
{
    var item = i;
    i.SubItems = (from n in li where n.ParentId == item.Id select n).ToList();
    i.SubItems.ForEach(f => RecursiveBuilder(ref f, li));
}

如果你不想要/有链接:

Dictionary<int,Item> dic = new Dictionary<int,Item>();
foreach(Item item in items)
{
    Item parent;
    if(item.ParentId!=null && dic.TryGetValue(item.ParentId, out parent))
        parent.SubItems.Add(item);
    else
        dic.Add(item.Id, item);
}
Item root = dic[1];

我假设总会有一个 id = 1 的项目,那就是树的根。

如果要使用不带 ID 的新类,请创建它们,而不是简单地将它们添加到其父级中。