C# C语言中的高速字符串匹配#
我在C# C语言中的高速字符串匹配#,c#,string,search,C#,String,Search,我在列表中有一个大约10000名员工的列表,我有一个列表框,其中包含这些员工的子集,具体取决于文本框中的搜索词 假设Staff对象具有以下公开属性: string FirstName string LastName string MiddleName int StaffID int CostCentre 我可以编写如下函数: bool staffMatchesSearch(Staff stf) { if (tbSrch.Text.Trim() == string.Empty)
列表
中有一个大约10000名员工的列表,我有一个列表框
,其中包含这些员工的子集,具体取决于文本框中的搜索词
假设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
框的内容时,都会重新评估筛选
这是可行的,速度也不算太慢,但我想知道我能不能让它更快一些
我曾尝试将整个过程重新编写为多线程,但由于只有10000名员工,开销似乎带走了大部分好处。此外,还有一系列其他的错误,比如如果搜索“John”,用户首先按下“J”来卷绕线程,但是当用户按下“o”时,在第一批有机会返回结果之前,另一组被卷绕。很多时候,结果会以杂乱无章的顺序返回,各种令人讨厌的事情都会发生
我可以想出一些调整,让最好的情况变得更好,但也会让最坏的情况变得更糟
你对如何改进这一点有什么想法吗
到目前为止,我已经实施了很多很好的建议,它们的效果如下:
- 在
事件上添加延迟,这样,如果用户在键盘上快速键入5个字符的名称,它只在末尾执行1次搜索,而不是连续执行5次搜索ValueChanged
- 预先计算
并存储在ToLower()
类中(作为Staff
属性,这样它就不会占用保存文件中的额外空间)[非序列化]
- 在
中添加一个Staff
属性,该属性将所有搜索条件作为单个、长、小写的串联字符串返回。然后对其运行单个get
。(此字符串存储在Contains()
对象中,因此只构造一次。)Staff
3) 当用户输入另一个字符时,不需要重新计算所有项目。输入字符只会减少匹配的数量,因此只会重新评估以前的匹配 4) 使用计时器在用户键入和启动搜索之间引入延迟。如果他们正在快速键入多个字符,您不妨等到他们暂停半秒钟
5) 检查按键是否按下。如果是NaN,则不检查int属性。您可以向Staff对象添加一个“SearchTerm”私有属性,该属性为
(FirstName+LastName+MiddleName+StaffID+costcenter)。ToLower()
,然后执行Contains()
检查。这将停止每次对每个字符串执行ToLower()
,并将Contains()
检查的数量从5减少到1。您可以尝试实现trie
或“前缀树”:
这将允许您搜索以值开头的文本
我相信关于的链接文章将允许您进行全文搜索,尽管它有更高的存储要求
确保在将数据插入到结构中时减少所有数据,这样在查找时就不必进行不区分大小写的比较。看到您所做的事情(主要是从@mikel的答案上的评论),听起来您已经做到了。我还没有看到一个可以提高速度的建议,就是使用
StringComparison.OrdinalIgnoreCase
进行比较。在你的情况下,这将意味着更换
if (stf.LastName.ToLower().Contains(s))
return true;
与
下面是一个示例,讨论快速字符串比较。使用系统;
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();
}
}
}
使用System.Text.RegularExpressions;
命名空间模式匹配1
{
班级计划
{
静态void Main(字符串[]参数)
{
尝试
{
WriteLine(“请输入第一个字符串”);
string str=Console.ReadLine();
字符串replacestr=Regex.Replace(str,“[^a-zA-Z0-9+”,”);
WriteLine(“请输入第二个字符串”);
字符串str1=Console.ReadLine();
字符串replacestr1=Regex.Replace(str1,“[^a-zA-Z0-9+”,”);
if(replacestr.Length==replacestr1.Length)
{
char[]cFirst=replacestr.ToLower().ToCharArray();
char[]cssecond=replacestr1.ToLower().ToCharArray();
Array.Sort(cFirst);
Array.Sort(秒);
if((新字符串(cFirst)).Equals((新字符串(cSecond)))
Console.WriteLine(“两个字符串相同”);
其他的
Console.WriteLine(“两个字符串不相同”);
}
其他的
WriteLine(“哎呀,出问题了!!!!再试一次”);
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}
Console.Read();
}
}
}
`你真的想
toString
那些int
s吗?似乎您需要matches string方法和matches int方法。。。我的意思是,如果我在13号中心,我不应该出现,因为有人搜索1号中心或3号中心…试着实现一个Boyer Moore系列的字符串搜索算法?预处理
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();
}
}
}