用Linq搜索层次数据

ulydmbyx  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(108)

我正在尝试根据How to search Hierarchical Data with Linq问题中提供的建议搜索分层数据,但是,我卡住了。

var NodeTypes = new NodeType[] {
    new NodeType{
      NodeTypeDescription = "First Level",
      Item = new CodeType(){  CodeValue = "01" },
      Node = new NodeType[]{
        new NodeType{
          NodeTypeDescription = "First Child Level 0101",
          Item = new CodeType(){  CodeValue = "0101" },
          Node = new NodeType[]{
            new NodeType{
              NodeTypeDescription = "Target Level Description",
              Item = new ModelType(){ ModelId = 1234, ModelTitle = "Target-1234" },
              Node = null
            }
          }
       },
       new NodeType{
         NodeTypeDescription = "First Child Level 0102",
         Item = new CodeType(){  CodeValue = "0102" },
         Node = new NodeType[]{
           new NodeType{
             NodeTypeDescription = "Target Level Description",
             Item = new ModelType(){ ModelId = 2345, ModelTitle = "Target-2345" },
            Node = null
           }
         }
       }
    }
   },
   new NodeType{
     NodeTypeDescription = "Second Level",
     Item = new CodeType(){  CodeValue = "02" },
     Node = new NodeType[]{
       new NodeType{
         NodeTypeDescription = "Second Child Level 0201",
         Item = new CodeType(){  CodeValue = "0201" },
         Node = new NodeType[]{
           new NodeType{
             NodeTypeDescription = "Second Child Level 020101",
             Item = new CodeType(){  CodeValue = "020101" },
             Node = new NodeType[]{
               new NodeType{
                 NodeTypeDescription = "Target Level Description",
                 Item = new ModelType(){ ModelId = 2345, ModelTitle = "Target-2345" },
                 Node = null
               }
             }
           }
         }
       },
       new NodeType{
         NodeTypeDescription = "Second Child Level 0202",
         Item = new CodeType(){  CodeValue = "0202" },
         Node = new NodeType[]{
           new NodeType{
             NodeTypeDescription = "Target Level Description",
             Item = new ModelType(){ ModelId = 3456, ModelTitle = "Target-3456" },
             Node = null
           }
         }
       }
     }
   }
 };

我已经把sample code放在这里了。

public static class Extensions
{
    public static IEnumerable<T> Flatten<T>(this T source, Func<T, IEnumerable<T>> selector)
    {
        return selector(source).SelectMany(c => Flatten(c, selector))
                               .Concat(new[] { source });
    }
}

public class ModelType
{
    public string ModelTitle;
    public long ModelId;
}

public class CodeType
{
    public string CodeValue;
}

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

public class Program
{
    public static void Main()
    {

        var NodeTypes = new NodeType[] {
                new NodeType{
                         NodeTypeDescription = "First Level",
                         Item = new CodeType(){  CodeValue = "01" },
                         Node = new NodeType[]{
                            new NodeType{
                                NodeTypeDescription = "First Child Level 0101",
                                Item = new CodeType(){  CodeValue = "0101" },
                                Node = new NodeType[]{
                                    new NodeType{
                                        NodeTypeDescription = "Target Level Description",
                                        Item = new ModelType(){ ModelId = 1234, ModelTitle = "Target-1234" },
                                        Node = null
                                    }
                                }
                            },
                            new NodeType{
                                NodeTypeDescription = "First Child Level 0102",
                                Item = new CodeType(){  CodeValue = "0102" },
                                Node = new NodeType[]{
                                    new NodeType{
                                        NodeTypeDescription = "Target Level Description",
                                        Item = new ModelType(){ ModelId = 2345, ModelTitle = "Target-2345" },
                                        Node = null
                                    }
                                }
                            }
                         }
                },
                new NodeType{
                         NodeTypeDescription = "Second Level",
                         Item = new CodeType(){  CodeValue = "02" },
                         Node = new NodeType[]{
                            new NodeType{
                                NodeTypeDescription = "Second Child Level 0201",
                                Item = new CodeType(){  CodeValue = "0201" },
                                Node = new NodeType[]{
                                    new NodeType{
                                        NodeTypeDescription = "Second Child Level 020101",
                                        Item = new CodeType(){  CodeValue = "020101" },
                                        Node = new NodeType[]{
                                            new NodeType{
                                                NodeTypeDescription = "Target Level Description",
                                                Item = new ModelType(){ ModelId = 2345, ModelTitle = "Target-2345" },
                                                Node = null
                                            }
                                        }
                                    }
                                }
                            },
                            new NodeType{
                                NodeTypeDescription = "Second Child Level 0202",
                                Item = new CodeType(){  CodeValue = "0202" },
                                Node = new NodeType[]{
                                    new NodeType{
                                        NodeTypeDescription = "Target Level Description",
                                        Item = new ModelType(){ ModelId = 3456, ModelTitle = "Target-3456" },
                                        Node = null
                                    }
                                }
                            }
                         }
                }
            };

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

我觉得这样不对

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

因为我想搜索所有节点并且目标节点可以在任何深度,
另一个问题...
在扁平化层次结构之后,我们如何从父节点或兄弟节点中获取细节呢?比如,我想从其父节点的兄弟节点Item中提取codeValue。

var result2 = DepthFirst<NodeType>(NodeTypes, n => n.Node).ToList(); 
var result1 = result2.Where(n => n.Item.GetType() == typeof(ModelType) && ((ModelType)n.Item).ModelId == 2345).ToList();
cbjzeqam

cbjzeqam1#

我更喜欢使用扩展方法来迭代树,类似于:

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);
                }
            }
        }

DepthFirst(nodeTypes, n => n.Node)一样调用,并生成树中所有节点的迭代器,而不管深度如何。来自链接答案的Flatten方法可能也会工作,因为它是递归的,但它可能会创建一个linq迭代器树,所以我认为它在进行迭代时会有大量的开销。
那么如果过滤掉您正在搜索的节点,这应该只是一个问题:

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

如果你想使用广度优先搜索,你只需用队列替换堆栈;如果你的图中可以有循环,你需要添加一个已访问节点的哈希集,并在遍历每个节点之前检查它。

bvjveswy

bvjveswy2#

您必须编写自己的flatten方法,如下所示

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;
        }
    }
    
}

相关问题