c# - 如何通过比较另一个列表中的每个节点来遍历树节点集合
问题描述
我有一个树视图,其中包含几个节点(超过 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);
}
}
有没有人有想法来提高这段代码的性能?
解决方案
此代码将几乎立即检查 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());
}
}
}
与发布版本的差异真的可以忽略不计:
所以这是一种不同的方法(从头开始编写),可能会给你一两个想法。
推荐阅读
- javascript - 编写一个表示 8×8 网格的程序?
- reactjs - 在不受控制的模态良好实践中使用 getDerivedStateFromProps
- electron - 电子应用程序中的 Microsoft Azure 登录失败
- javascript - 如何在javascript中使用对象数组
- javascript - GoogleAuth javascript API 未检测到已登录的用户
- python - 是否可以根据不同的输入信息创建函数?
- kotlin - Kotlin:val mutableList 与 var immutableList。什么时候用哪个?
- android - Android ARCore 在 ViewRenderable 中使用 TextureView
- java - Spring Boot Actuator 不工作并且 application.properties 在 STS 中是未知的
- javascript - 了解 Chart.js 并为饼图添加图例