将列表转换为树

时间:2013-06-28 19:14:58

标签: c# linq list tree

是否可以将List转换为Tree,以便在删除父节点时自动删除所有子节点?

这样做的原因是我有递归类别,我希望显示除​​子类别之外的所有类别(递归),并且在我的脑海中最简单的方法是执行类似图片中的操作。

正如您在此场景中看到的,当我删除红色节点时,所有绿色节点都将自动删除。我有什么选择?

Tree

这是我正在使用的模型,如果它有任何区别。

public class Category
{
    public int Id { get; set; }

    public int? RootCategoryId { get; set; }
    public virtual Category RootCategory { get; set; }
    public virtual ICollection<Category> ChildCategories { get; set; }
}

这是我到目前为止所拥有的

// This would eliminate only current category but not its children = bad
var availableCategories = _db.Categories.Where(x => x.Id != currentlyEditedId);

因此,例如,当我想编辑某个类别时,我会调用_db.Categories.Where(x => x.Id != currentlyEditedId);。这将消除当前类别(在图片中它将删除红色的一个)但是绿色的类别将保留。

我如何确保如果删除红色的那个绿色也会删除?

最后,我想要一张包含图片中所有黑色项目的列表。

2 个答案:

答案 0 :(得分:1)

要删除项目,您需要逐个删除它们;这就是db上下文的工作原理。你可以简单地删除所有要删除的项目。以下是遍历树的简单算法:

public static IEnumerable<Category> Traverse(Category root)
{
    var stack = new Stack<Category>();

    stack.Push(root);

    while (stack.Any())
    {
        var next = stack.Pop();
        yield return next;
        foreach (var child in next.ChildCategories)
            stack.Push(child);
    }
}

现在您可以执行以下操作:

public static void DeleteCategory(Category category)
{
    var items = Traverse(category).ToList();
    var itemsToDelete = _db.Categories.Where(cat => items.Contains(cat));
    //delete items
}

如果你只是想从内存中删除一个项目,那么你只需要在它的父级上调用Remove。如果您没有父节点,并且只有要删除的节点和根节点,那么您需要使用另一种方法来遍历树:

public static bool Remove(Category root, int id)
{
    var stack = new Stack<Category>();

    stack.Push(root);

    while (stack.Any())
    {
        var next = stack.Pop();
        foreach (var child in next.ChildCategories)
        {
            if (child.Id == id)
            {
                next.ChildCategories.Remove(child);
                return true;
            }
            stack.Push(child);
        }
    }

    return false;
}

答案 1 :(得分:1)

这就是我想要的。传入类别列表并删除当前的列表并递归删除其所有子项。

/// <summary>
/// Get list of all categories except current one as well as all it's child categories
/// </summary>
/// <param name="id">Current category id</param>
/// <param name="categories">List of categories</param>
/// <returns>List of categories</returns>
public static List<Category> CategoriesWithoutChildren(int id, List<Category> categories)
{
    var currentCategory = categories.Single(x => x.Id == id);
    categories.Remove(currentCategory);

    if (currentCategory.ChildCategories.Count > 0)
    {
        currentCategory.ChildCategories.ToList().ForEach(x =>
        {
            categories = CategoriesWithoutChildren(x.Id, categories);
        });
    }

    return categories;
}