C# 制作Intellisense/Autocomplete列表时,过滤字符串列表的最快方法是什么?

C# 制作Intellisense/Autocomplete列表时,过滤字符串列表的最快方法是什么?,c#,.net,wpf,linq,intellisense,C#,.net,Wpf,Linq,Intellisense,我正在写一个Intellisense/Autocomplete,就像你在VisualStudio中找到的那样。在列表中包含2000多个项目之前,一切都很好 我使用一个简单的LINQ语句进行过滤: var filterCollection = from s in listCollection where s.FilterValue.IndexOf(currentWord, StringCompar

我正在写一个Intellisense/Autocomplete,就像你在VisualStudio中找到的那样。在列表中包含2000多个项目之前,一切都很好

我使用一个简单的LINQ语句进行过滤:

var filterCollection = from s in listCollection
                       where s.FilterValue.IndexOf(currentWord,     
                       StringComparison.OrdinalIgnoreCase) >= 0
                       orderby s.FilterValue
                       select s;
然后我将此集合分配给WPF Listbox的ItemSource,到此结束,一切正常

注意,Listbox也是虚拟化的,因此在内存和可视化树中最多只有7-8个可视化元素

然而,现在需要注意的是,当用户在richtextbox中以极快的速度键入时,我在每个键上执行过滤+绑定,就会出现这种半竞争条件,或者不同步过滤,就像第一个按键的过滤仍然可以执行过滤或绑定工作一样,而第四个击键也是这样做的

我知道我可以在应用过滤器之前延迟一段时间,但我正试图实现一个无缝过滤,就像VisualStudio中的一样

我不确定我的问题到底出在哪里,所以我也将其归因于IndexOf的字符串操作,或者我的字符串列表可以在某种索引中进行优化,从而加快搜索速度

欢迎对代码示例的任何建议


谢谢。

我建议尝试将结果集限制在一定数量的项目上,看看问题是否消失。也就是说,您可能有5000个选项可供选择,但尝试返回的值不超过100,即使更多匹配项也是如此。说:

var filterCollection = (from s in listCollection
  where s.FilterValue.IndexOf(currentWord,StringComparison.OrdinalIgnoreCase)>=0
  orderby s.FilterValue
  select s).Take(100);
如果您的问题消失,则可能是由于为列表框返回的项目太多而导致的。我不确定这个问题是否会消失,因为ListBox是虚拟化的,但值得一试。您也可以尝试同样的方法,但将筛选结果限制为100项,然后再进行排序(即orderby),看看这是否有帮助。无论如何,按这种顺序做会更有效:

var filterCollection = (from s in listCollection
  where s.FilterValue.IndexOf(currentWord,StringComparison.OrdinalIgnoreCase)>=0
  select s).Take(100)
           .OrderBy(s => s.FilterValue);

底线是确定问题是返回并分配给FilterContaction的项目数的函数,还是初始项目数的函数,或者两者都有。

如果结果集为2000个项目,则延迟不是问题。我在这里做了一些大的假设,但是您实际上最多只需要返回500个项目-您的用户将继续键入以缩小结果集的范围,直到它达到可接受的浏览大小


您应该优化常见情况(我假设它最终会有大约50个项目)-如果您的用户滚动浏览2000个项目的小列表,则会出现其他问题,界面需要更多工作。

一个非常简单的优化是

if(currentWord.StartsWith(lastWord))
您可以在上次查询返回的已筛选项列表上进行筛选。也就是说,除非按照其他一些答案的建议减少LINQ查询返回的项目数。您可以始终将查询中的内容存储在一个变量中,然后再执行Take(100),尽管在这种情况下需要确保LINQ的延迟执行不会影响您


在绑定端,您可以使用一个
ObservableCollection
来添加/删除项目,而不是替换整个集合。如果你想这样做,倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来倒过来,也就是说,它必须检查每个项目,以确定哪些项目与之匹配。项目越多,过滤器的性能越差

不要使用列表,而是尝试使用。尝试执行
O(m)
,其中
m
是字符串中的字符数。这意味着数据集的大小不会影响查找的性能

在(我编写的一个应用程序启动器)中,我在intellisense/autocomplete中使用了trytes。如果您想查看正在进行的尝试示例,您可以下载并试用。

这是您的“竞赛条件”

考虑字母序列d,o,g

  • “d”开始运行,并将匹配设定值的30%。必须订购6000件物品
  • “do”开始运行,并将匹配设定值的6%。必须订购1200件物品
  • “狗”开始跑,并将匹配设定值的0.5%。必须订购100件商品
在考虑每个事件的不同工作负载时,毫不奇怪最后一个事件将在第一个和第二个事件之前完成


我能想象的最正确的行为是在事件开始时防止绑定任何先前的活动事件。如果可以通过停止这些事件的执行来防止绑定,那就更好了。回想一下那些导弹,它们已经没有目标了。

你确认过这实际上是瓶颈吗?我只是好奇是否还有其他代码可能起作用,如果不进行分析,您就无法确定瓶颈在哪里+顺便说一句,我喜欢这样的问题。嗨,安德鲁,我很高兴我问了一个启发性的问题:)。这只是一个假设,我指的是过滤或绑定到控件,这是瓶颈。我也不完全确定你是否真的可以拥有一个intellisense/autocomplete列表功能,该功能在如此多的项目和不断增长的项目中表现得非常出色。我不太擅长使用分析工具,关于如何分析这一点,你有什么好的建议吗?我尝试了visual studio中的一个,但是漂亮的图形指向应用程序。运行=(你确定ListBox被正确虚拟化了吗,因为这个实际的过滤代码应该在一毫秒内运行?肯定是虚拟化的。正如我提到的,它会快速上升,直到达到数千个范围。这是一个非常有效的点,因为该功能的目的是缩小结果。但是,理论上,如果他们只是键入
orderby s.FilterValue