首页 > 解决方案 > 如何通过比较另一个列表中的每个节点来遍历树节点集合

问题描述

我有一个树视图,其中包含几个节点(超过 100.000 个)和复选框,代表文件夹/文件。

除此之外,我还有一个可能包含 10-20 个元素的字符串列表。

我想遍历所有树并检查每个节点是否节点的完整路径包含在该字符串列表中,如果是,则比我为该节点设置复选框。

我的问题是性能。如果字符串列表包含超过 2-3 个元素,则程序需要很长时间才能显示结果。

这是我的代码:

void SetCheckedNodes(TreeNodeCollection allNodes, IEnumerable<string> excludedFiles)
{
    foreach (TreeNode node in allNodes)
    {
        foreach (string ef in excludedFiles)
        {
            if (ef == node.FullPath)
            {
                node.Checked = true;
            }
        }

        if (node.Nodes.Count > 0)
            SetCheckedNodes(node.Nodes, excludedFiles);
    }
}

有没有人有想法来提高这段代码的性能?

标签: c#algorithmwinforms

解决方案


此代码将几乎立即检查 100000 上的大约 1000 个项目:

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // assuming tree view has a root node already

            treeView1.CheckBoxes = true;
            treeView1.BeginUpdate();

            var builder = new StringBuilder();

            // read first 100000 paths from a file
            var watch = Stopwatch.StartNew();
            var lines = File.ReadAllLines(@"C:\temp\files.txt").Take(100000).ToArray();
            builder.AppendLine($"Time taken reading paths: {watch.Elapsed}");

            // populate tree view with these paths
            watch.Restart();
            foreach (var line in lines)
            {
                var root = treeView1.TopNode;
                var keys = line.Split(Path.DirectorySeparatorChar);

                foreach (var key in keys)
                {
                    var nodes = root.Nodes;
                    root = nodes.ContainsKey(key) ? nodes[key] : nodes.Add(key, key);
                }
            }

            builder.AppendLine($"Time taken populating tree: {watch.Elapsed}");

            // add some garbage and shuffle
            watch.Restart();
            var range = Enumerable.Range(0, 1000).ToArray();
            var random = new Random();
            var strings = range.Select(s => lines[random.Next(lines.Length)]);
            var garbage = range.Select(s => s.ToString());
            var array = strings.Concat(garbage).OrderBy(s => random.Next());
            builder.AppendLine($"Time taken randomizing: {watch.Elapsed}");

            // now check checkable items
            watch.Restart();
            foreach (var line in array)
            {
                var root = treeView1.TopNode;
                var keys = line.Split(Path.DirectorySeparatorChar);

                foreach (var key in keys)
                {
                    var nodes = root.Nodes;

                    root = nodes.ContainsKey(key) ? nodes[key] : null;

                    if (root == null)
                        break;
                }

                if (root == null)
                    continue;

                root.Checked = true;
            }

            builder.AppendLine($"Time taken checking items: {watch.Elapsed}");

            treeView1.EndUpdate();

            MessageBox.Show(builder.ToString());
        }
    }
}

与发布版本的差异真的可以忽略不计:

在此处输入图像描述

所以这是一种不同的方法(从头开始编写),可能会给你一两个想法。


推荐阅读