I am trying to search hierarchical data based on the advice provided in this question
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;
}
}
}