我在List<T>
中列出了大约10,000名员工,我有一个ListBox
,其中包含这些员工的子集,具体取决于文本框中的搜索字词。
假设Staff
对象具有以下公开公开的属性:
string FirstName
string LastName
string MiddleName
int StaffID
int CostCentre
我可以写一个这样的函数:
bool staffMatchesSearch(Staff stf)
{
if (tbSrch.Text.Trim() == string.Empty)
return true; // No search = match always.
string s = tbSrch.Text.Trim().ToLower();
// Do the checks in the order most likely to return soonest:
if (stf.LastName.ToLower().Contains(s))
return true;
if (stf.FirstName.ToLower().Contains(s))
return true;
if (stf.MiddleName.ToLower().Contains(s))
return true;
if (stf.CostCentre.ToString().Contains(s))
return true; // Yes, we want partial matches on CostCentre
if (stf.StaffID.ToString().Contains(s))
return true; // And also on StaffID
return false;
}
然后执行以下操作:
tbSrch_TextChanged(object sender, EventArgs e)
{
lbStaff.BeginUpdate();
lbStaff.Items.Clear();
foreach (Staff stf in staff)
if (staffMatchesSearch(stf))
lbStaff.Items.Add(stf);
lbStaff.EndUpdate();
}
每次用户更改tbSrch
框的内容时,都会重新评估过滤。
这很有效,并且非常慢,但我想知道我是否可以更快地制作它?
我试图将整个事情重新编写为多线程,但只有10,000名员工,开销似乎带走了大部分收益。此外,还有一堆其他错误,如果搜索&#34; John&#34;,用户首先按下&#34; J&#34;它会线程化线程,但当用户按下&#34; o&#34;在第一批有机会返回结果之前,另一组被假脱机。很多时候,结果会以混乱的顺序返回,并且会发生各种令人讨厌的事情。
我可以想到一些调整可以使最佳情况显着改善,但它们也会使最坏情况更糟糕。
您对如何改进这一点有什么想法吗?
我已经实施的很好的建议及其结果:
ValueChanged
事件上添加延迟,以便在用户在键盘上快速键入5个字符的名称时,它最后只执行1次搜索而不是5次串行搜索。ToLower()
并存储在Staff
类中(作为[NonSerialized]
属性,因此它不会占用保存文件中的额外空间。)get
中添加Staff
属性,该属性将所有搜索条件作为单个长小写连接字符串返回。然后在其上运行一个Contains()
。 (此字符串存储在Staff
对象中,因此只构造一次。)到目前为止,这些搜索时间从大约140毫秒降低到大约60毫秒(尽管这些数字非常主观,具体取决于实际执行的搜索和返回的结果数量。)
答案 0 :(得分:7)
1)正如评论中所指出的,你可能不应该.ToString数字字段 - 只匹配数字
2)ToLower调用是一个perf漏洞。将这些属性的小写版本添加到Staff类,因此ToLower只需要执行一次
3)当用户输入另一个字符时,您无需重新评估所有项目。输入一个字符只会减少匹配次数,所以只能重新评估之前的匹配。
4)使用计时器在用户输入和开始搜索之间引入延迟。如果他们快速输入多个字符,你可能要等到他们暂停了半秒
5)检查按下的键。如果NaN则不检查int属性。
答案 1 :(得分:2)
您可以将“SearchTerm”私有属性添加到(FirstName + LastName + MiddleName + StaffID + CostCentre).ToLower()
的Staff对象,然后执行Contains()
检查。这将阻止您每次对每个字符串执行ToLower()
,并将Contains()
个检查的数量从5减少到1。
答案 2 :(得分:2)
您可以尝试实施trie
或“前缀树”:
http://en.wikipedia.org/wiki/Trie
这将允许您使用值搜索开始的文本。
我相信suffix-trees上的链接文章会允许您进行全文搜索,但它具有更高的存储要求。
在将结果插入结构时,请确保ToLower
所有数据,这样您在查找时就不必进行不区分大小写的比较。
答案 3 :(得分:1)
看到你做过的事情(主要来自对@ mikel回答的评论),听起来就像你到了那里。我没有看到哪个可以提高速度的建议是使用StringComparison.OrdinalIgnoreCase
进行比较。在您的情况下,这将意味着替换
if (stf.LastName.ToLower().Contains(s))
return true;
与
if (stf.LastName.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0)
return true;
这是MSDN link,讨论快速字符串比较。
答案 4 :(得分:0)
using System;
using System.Text.RegularExpressions;
namespace PatternMatching1
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Please enter the first string.");
string str = Console.ReadLine(); ;
string replacestr = Regex.Replace(str, "[^a-zA-Z0-9_]+", " ");
Console.WriteLine("Please enter the second string.");
string str1 = Console.ReadLine(); ;
string replacestr1 = Regex.Replace(str1, "[^a-zA-Z0-9_]+", " ");
if (replacestr.Length == replacestr1.Length)
{
char[] cFirst = replacestr.ToLower().ToCharArray();
char[] cSecond = replacestr1.ToLower().ToCharArray();
Array.Sort<char>(cFirst);
Array.Sort<char>(cSecond);
if ((new string(cFirst)).Equals((new string(cSecond))))
Console.WriteLine("Both String Same");
else
Console.WriteLine("Both String Not Same");
}
else
Console.WriteLine("oopsss, something going wrong !!!! try again");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
}
`