Remove object from hierarchical collection

I have a set of NodeObject classes in a hierarchical list. The list may contain any number of levels.

public class NodeModel : ViewModelBase
{
    public Guid Id { get; set; }
    public string Caption { get; set; }
    public string Description { get; set; }
    public NodeType Type { get; set; }
    public List<NodeModel> Children { get; set; }
}

How to remove an item from the list using its Guid identifier no matter where it is in the list?

+3
source share
3 answers

Here's a recursive way to do this:

private void DeleteNode(IList<Node> nodes, Guid id)
{
    Node nodeToDelete = null;
    foreach (var node in nodes)
    {
        if (node.Id == id)
        {
            nodeToDelete = node;
            break;
        }
        DeleteNode(node.Children, id);
    }
    if (nodeToDelete != null)
    {
        nodes.Remove(nodeToDelete);
    }
}

If you want to have all the operations in one loop, do it with a for loop. In my opinion, this is much harder to read.

private void DeleteNode(IList<Node> nodes, int id)
{
    for (var index = 0; index < nodes.Count; index++)
    {
        var currentNode = nodes[index];
        if (currentNode.Id == id)
        {
            nodes.Remove(currentNode);
            break;
        }
        DeleteNode(currentNode.Children, id);
    }
}

() ( !), . , . , , . , :

private void DeleteNode(IList<Node> flatNodes, Guid id)
{
    var nodeToDelete = flatNodes.FirstOrDefault(n => n.Id == id);
    if (nodeToDelete != null)
    {
        var parent = flatNodes.First(n => n.Id == nodeToDelete.ParentId);
        parent.Children.Remove(nodeToDelete);
    }
}

private void DeleteNodeFromFlatDictionary(IDictionary<Guid, Node> flatNodes, Guid id)
{
    if (!flatNodes.ContainsKey(id)) return;
    var nodeToDelete = flatNodes[id];
    parent[nodeToDelete.ParentId].Children.Remove(id);
}

, , ObservableCollection<Node>.

+7

, LINQ- script, . , - , , :

public void RemoveNodeModelByGuid(NodeModel root, Guid guid)
{
    Stack<NodeModel> nodes = new Stack<NodeModel>();
    nodes.Add(root);

    while (nodes.Count > 0)
    {
        var currentNode = nodes.Pop();
        for (int i = currentNode.Children.Count - 1; i >= 0; i--)
        {
            if (currentNode.Children[i].Id == guid)
                currentNode.Children.RemoveAt(i);
            else
                nodes.Push(currentNode.Children[i]);
        }
    }
}

, "root" node ( , ), , , . , , Guid (, , , node , ). , node , .

0

, . :

  • ? Node A , B, B C C A (A β†’ B β†’ C β†’ A ..)
  • ?
  • ?

Problem with deleting an item - what are you doing with childern? What if the root got sam guid? The best solution is to cross the tree and get a set of nodes.

public static IEnumerable<T> Traverse<T>(T root, Func<T, IEnumerable<T>> children)
{
    var seen = new HashSet<T>();
    var stack = new Stack<T>();
    stack.Push(root);

    while(stack.Count != 0)
    {
        T item = stack.Pop();
        if (seen.Contains(item))
            continue;
        seen.Add(item);
        yield return item;
        foreach(var child in children(item))
            stack.Push(child);
    }
}

Then to call

var nodes = Traverse<NodeModel>(root, node => node.Children).ToList();

And now you can remove () the item from the list or filter it with Where ().

0
source