繁体   English   中英

在列表中查找课程

[英]Finding a class within list

我有一个类(节点),它具有SubNodes的属性,该属性是Node类的列表

我有一个节点列表(其中每个节点本身可能有也可能没有子节点列表),我需要能够在节点列表/子节点中找到一个节点。

我试图在列表上进行查找,但是只会搜索列表中的节点类,而不是子节点列表。 查看了C5库和一些二进制树,但找不到合适的东西。 有什么建议吗?

班级

 public class Node
 {
        public Guid Id { get; set; }
        public DateTime Created { get; set; }
        public List<Node> Nodes { get;set;}
 }

函数(结果为最终结果)

private void GetRecersive(List<Node> list, ref List<Node> result)
        {
            foreach (Node item in list)
            {

                if (item.ParentId.Equals(Guid.Empty))
                {
                    result.Add(item);
                }
                else
                {
                    result.ForEach(x => x.FindNodes(y => y.Id.Equals(item.ParentId)).FirstOrDefault().Nodes.Add(item));
                }

                List<Node> nodes = GetNodesByParent(item.Id);

                GetRecersive(nodes, ref result);
            }
        }

正如empi所说,递归搜索是理想的选择。 如果您确实有一棵树,即没有循环,那么就这么简单:

public class Node
{
    // Properties as before

    public Node FindById(Guid id)
    {
        if (id == Id)
        {
            return this;
        }
        foreach (Node node in Nodes)
        {
            Node found = node.FindById(id);
            if (found != null)
            {
                return found;
            }
        }
        return null; // Not found in this subtree
    }
}

否则,您需要保留一组已经访问过的节点(例如HashSet<Node> )。 周期使各种事情变得令人讨厌:)

可以使用LINQ重写foreach循环:

return Nodes.Select(x => x.FindById(id)).FirstOrDefault();

但是我不确定在这种特殊情况下,它是否真的像显式循环那样清晰(尽管我是LINQ的忠实拥护者)。

您可以添加样式化层次结构并使用LINQ的代码:

public class Node
{
    // Properties

    public IEnumerable<Node> AllNodes
    {
        get
        {
            yield return this;

            foreach (var node in Nodes.SelectMany(n => n.AllNodes))
                yield return node;
        }
    }
}

并使用LINQ来对象:

var matches = nodes.SelectMany(n => n.AllNodes).Where(n => n.Created < DateTime.Today);

您将必须递归搜索(在“节点”列表中搜索,然后在先前“节点”列表中每个节点的“节点”列表中搜索,依此类推)并保留已访问节点的列表(否则,如果结构中存在循环,则将永远无法完成) )。 您是否尝试过这样做?

这是无论深度有多深,我都会这样做的方法:

Node类:

public class Node
{
    public Guid Id { get; set; }
    public DateTime Created { get; set; }
    public List<Node> Nodes { get; set; }

    public Node()
    {
        this.Nodes = new List<Node>();
    }

    public List<Node> FindNodes(Func<Node, bool> condition)
    {
        List<Node> resList = new List<Node>();

        if (this.Nodes != null && this.Nodes.Count > 0)
        {
            this.Nodes.ForEach(x =>
                {
                    resList.AddRange(x.FindNodes(condition));
                    if (condition(x))
                        resList.Add(x);
                }
            );
        }

        return resList;
    }
}

例如,具有以下节点列表:

List<Node> nodeList = new List<Node>()
{
    new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 10), 
        Nodes = { 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 11) }, 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 12) } } },
    new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 10), 
        Nodes = { 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 11), 
                Nodes = {
                    new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 11, 11) }, 
                    new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 12, 12),
                        Nodes = {
                            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2011, 11, 11) }, 
                            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2011, 12, 12) } } } } }, 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 12) } } },
    new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 10), 
        Nodes = { 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 11) }, 
            new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 12) } } },
};

我可以找到我想要的任何子节点:

List<Node> resList = new List<Node>();

nodeList.ForEach(x =>
    resList.AddRange(x.FindNodes(y => y.Created.Day == 12)));

您可以随便看什么。 在上面的示例中,我搜索在任何月份和年份的第12天创建的节点。

看来我们所有人都已经把事情复杂化了。 我向我的一位同事展示了该问题,他制作了下面的作品,该作品效果很好。

private void BuildUpChildren(List<Node> list)
        {
            foreach (Node item in list)
            {
                List<Node> nodes = GetNodesByParent(item.Id);
                item.Nodes.AddRange(nodes);
                BuildUpChildren(nodes);
            }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM