C# 如何从列表中删除特定节点

C# How to remove specific nodes from list

我有以下class

public class Item
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Content { get; set; }
    public bool IsLastItem { get; set; }
}

假设我有以下模型,我想删除 IsLastItem = false 并且没有子项的项目。在这种情况下,item4 和 item7 应该从列表中删除。

我从数据库中获取我的模型列表,并在代码块中像这样模拟它

var items = new List<Item>
{
    new Item
    {
        Id = 1,
        ParentId = 0,
        Content = "item1",
        IsLastItem = false
    },
    new Item
    {
        Id = 2,
        ParentId = 1,
        Content = "item2",
        IsLastItem = false
    },
    new Item
    {
        Id = 3,
        ParentId = 1,
        Content = "item3",
        IsLastItem = true
    },
    new Item
    {
        Id = 4,
        ParentId = 1,
        Content = "item4",
        IsLastItem = false
    },
    new Item
    {
        Id = 5,
        ParentId = 2,
        Content = "item5",
        IsLastItem = false
    },
    new Item
    {
        Id = 6,
        ParentId = 5,
        Content = "item6",
        IsLastItem = false
    },
    new Item
    {
        Id = 7,
        ParentId = 5,
        Content = "item7",
        IsLastItem = false
    },
    new Item
    {
        Id = 8,
        ParentId = 6,
        Content = "item8",
        IsLastItem = true
    },
    new Item
    {
        Id = 9,
        ParentId = 8,
        Content = "item9",
        IsLastItem = true
    }
};

您忘记在模拟数据中设置 IsLastItem,仅供参考。您应该可以使用 RemoveAll.

来完成此操作
public static void Main()
{
    var items = init();
    items.RemoveAll(x => !items.Any(y => y.ParentId == x.Id) == true && x.IsLastItem == false);         

}

public static List<Item> init()
{           
    return new List<Item>
    {
        new Item
        {
            Id = 1,
            ParentId = 0,
            Content = "item1"
        },
            new Item
        {
            Id = 2,
            ParentId = 1,
            Content = "item2"
        },
            new Item
        {
            Id = 3,
            ParentId = 1,
            Content = "item3",
            IsLastItem = true
        },
            new Item
        {
            Id = 4,
            ParentId = 1,
            Content = "item4"
        },
            new Item
        {
            Id = 5,
            ParentId = 2,
            Content = "item5"
        },
            new Item
        {
            Id = 6,
            ParentId = 5,
            Content = "item6"
        },
            new Item
        {
            Id = 7,
            ParentId = 5,
            Content = "item7"
        },
            new Item
        {
            Id = 8,
            ParentId = 6,
            Content = "item8"
        },
            new Item
        {
            Id = 9,
            ParentId = 8,
            Content = "item9",
            IsLastItem = true
        }
    };      
}

像这样的平面列表对于这些类型的操作来说并不是最佳选择 - 如果您能以某种树结构恢复列表(可能 return 它来自 SQL 可能会更好使用 FOR XML 或 JSON 如果你在 2016 年)开始,你可以更轻松地遍历树。

另请注意,您的样本数据并未设置 IsLastItem...

照原样,您必须至少迭代两次,如下所示:

items.RemoveAll(x => x.IsLastItem == false && 
    items.Any(y => y.ParentId == x.Id) == false);

您是说要删除所有 IsLastItem 为假且没有至少一项的父 ID 是该项 ID 的项目。

找到 ParentIds。将每个项目与 ParentId 集合的列表进行比较并检查 IsLastitem。

var parents = items.Select(x => x.ParentId);
items.RemoveAll(x => !parents.Contains(x.Id) && !x.IsLastItem);

我建议您使用 tree-like 结构,并使 IsLastItem 成为计算的 属性:

public class Item
{
    public int Id { get; set; }
    public string Content { get; set; }
    public List<Item> SubItems { get; set; }
    public bool IsLastItem { get { return SubItems.Count == 0; } }
}

由于存储在数据库中的项目将具有平面结构,因此您必须编写一个函数来从数据库创建树(并在必要时将树写出到数据库),但是一旦完成,树会更容易操作。

然后您将编写一个递归函数来删除所有最后的节点,如下所示:

List<Item> RemoveNodes(List<Item> tree)
{
    var ret = tree.Where(item => !item.IsLastItem);
    foreach (Item item in ret)
    {
        item.SubItems = RemoveNodes(item.SubItems);
    }
    return ret;
}

这可能不是最好的方法,但您明白了。