Home > Enterprise >  Search Hierarchical Data Using Linq
Search Hierarchical Data Using Linq

Time:07-23

I am trying to search hierarchical data based on the advice provided in this question enter image description here

I have placed the sample code here.

I don't think this is right

var result = NodeTypes[0].Flatten(x => x.Node).Where(y => ((ModelType)(y.Item)).ModelId == 2345);

as I want to search all nodes and the target node could be at any depth,

CodePudding user response:

I prefer to use a extension method to iterate the tree, something like:

        public static IEnumerable<T> DepthFirst<T>(IEnumerable<T> roots, Func<T, IEnumerable<T>> selector)
        {
            var stack = new Stack<T>();
            foreach (var r in roots)
            {
                stack.Push(r);
            }
            while (stack.Count > 0)
            {
                var current = stack.Pop();
                yield return current;
                foreach (var child in selector(current))
                {
                    stack.Push(child);
                }
            }
        }

Called like DepthFirst(nodeTypes, n => n.Node), and produces a iterator of all nodes in the tree, regardless of depth. The Flatten method from the linked answer should probably also work, since it is recursive, but it will likely create a tree of linq iterators, so I would expect it to have substantial overhead when doing the iteration.

Then it should simply be an issue if filtering out the nodes you are searching for:

DepthFirst(nodeTypes, n => n.Node).Where(n => n.Item.ModelId == 2345);

If you want to do a BreadthFirst search instead you simply replace the stack with a queue. If you can have cycles in your graph you need to add a hashSet of visited nodes, and check this before traversing each node.

CodePudding user response:

You have to write your own flatten method like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication35
{
    class Program
    {
        static void Main(string[] args)
        {
            NodeType root = new NodeType()
                {
                    NodeTypeDescription = "abc",
                    Item = new ModelType() { ModelId = 123, ModelTitle = "123" },
                    Node = new NodeType[] {
                        new NodeType() { Item = "456", Node = null, NodeTypeDescription = "empty"},
                        new NodeType() { Item = "789", Node = null, NodeTypeDescription = "empty"},
                        new NodeType() { Item = "abc", Node = null, NodeTypeDescription = "empty"},
                    }
                };
            Dictionary<long, ModelType> nodes = root.Flaten(root);
           
        }
    }
    public class ModelType
    {
        public string ModelTitle;
        public long ModelId;
    }

    public class NodeType
    {
        public string NodeTypeDescription { get; set; }
        public object Item { get; set; }
        public NodeType[] Node { get; set; }

        public Dictionary<long, ModelType> Flaten(NodeType node)
        {
            Dictionary<long, ModelType> models = null;
            List<KeyValuePair<long, ModelType>> children = node.FlatenRecursive(node);

            if (node.GetType() == typeof(ModelType))
            {
                models = new Dictionary<long, ModelType>(); 

                models.Add(((ModelType)node.Item).ModelId, (ModelType)node.Item);
            }
            if (children != null)
            {
                foreach (KeyValuePair<long, ModelType> child in children)
                {
                    if (models == null) models = new Dictionary<long, ModelType>();
                    models.Add(child.Key, child.Value);
                }
            }
            return models;
        }
        public List<KeyValuePair<long,ModelType>> FlatenRecursive(NodeType node)
        {
            List<KeyValuePair<long, ModelType>> models = null;
            if(node.Item.GetType() == typeof(ModelType))
            {
                models = new List<KeyValuePair<long, ModelType>>();
                models.Add(new KeyValuePair<long,ModelType>(((ModelType)node.Item).ModelId, (ModelType)node.Item));
            }
            if (node.Node != null)
            {
                foreach (NodeType child in node.Node)
                {
                    List<KeyValuePair<long, ModelType>> children = child.FlatenRecursive(child);
                    if (children != null)
                    {
                        if (models == null) models = new List<KeyValuePair<long, ModelType>>();
                        models.AddRange(children);
                    }
                   
                }
            }
            return models;
        }
    }
    
}
  • Related