[英]Is this the most efficient way to search for a substring?
我正在处理一些代码,这些代码返回一个代码来指示它们的用户类型(例如“A”,“B”,“C”,“D”等)。 每个代码对应于特定的角色和/或范围(例如,跨整个应用程序或仅针对正在处理的对象)。
在我正在查看的一些代码中,我看到调用以检查用户的代码是否是其中之一,以便允许它们执行某些操作。 所以我看到如下调用:
//"B" would come from the database
string userCode = "B";
//some more work...
//if the user's code is either A or C...
if("AC".IndexOf(userCode) >= 0) {
//do work that allows the user to progress
} else {
//notify user they can't do this operation
}
这是执行此检查的有效方式吗? 有更有效的方法吗?
提前致谢!
看看Contains()
的解编译代码,它只是用StringComparison.Ordinal
调用IndexOf()
,所以我说IndexOf()
是最有效的(通过一个非常小的头发)我如果以相同的方式使用(Ordinal) )因为它有一个较少的方法调用,但Contains()
更易读,因此更易于维护...
public bool Contains(string value)
{
return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}
就像在所有事情中一样,我会选择更具可读性和可维护性的东西,然后分解性能。 当你知道此时存在瓶颈时,才进行微优化。
更新 :超过1,000,000次迭代:
所以你可以看到,非常非常接近。 再一次,使用更可维护的东西。
更新2 :如果您的代码始终是单个char(不是1-char字符串),则IndexOf()更快:
如果你知道你的char代码总是一个char,那么使用带有char参数的IndexOf()
大约要快一个数量级。
这是因为Contains(char value)
是IEnumerable<T>
的扩展方法,而不是string
的第一类方法。
但是 ,超过1,000,000次迭代再次~100 ms真的,真的,可以忽略不计。
如果您正在寻找单个字符,并且它不区分大小写,请使用与char一起使用的重载。 搜索单个不区分大小写的char比子字符串更快。
"AC".IndexOf('C');
尽管如此,这对于物质来说必须是可笑的性能。 使用任何明显的方法,你正在做的事情会非常快。
更新 - 计时
[Test]
public void Time()
{
const string UserCode = "C";
const char UserCodeChar = 'C';
const int Iterations = 10000000;
double adjust = 0;
Func<Action, double> time = action =>
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++) action();
return sw.Elapsed.TotalMilliseconds;
};
Action<string, Action> test = (desc, t) =>
{
double ms = time(t) - adjust;
Console.WriteLine(desc + " time: {0}ms", ms);
};
adjust = time(() => { });
test("IndexOfString", () => "AC".IndexOf(UserCode));
test("IndexOfString", () => "AC".IndexOf(UserCode));
test("ContainsString", () => "AC".Contains(UserCode));
test("ContainsString", () => "AC".Contains(UserCode));
test("IndexOfChar", () => "AC".IndexOf(UserCodeChar));
test("IndexOfChar", () => "AC".IndexOf(UserCodeChar));
}
结果:
IndexOfString时间:1035.2984ms
IndexOfString时间:1026.2889ms
包含字符串时间:764.9274ms
包含字符串时间:736.7621ms
IndexOfChar时间:92.9008ms
IndexOfChar时间:92.9961ms
我认为您可以假设系统库的实现非常高效,并且您通常无法使用自制解决方案加快速度。 也就是说,我认为你对用户类型进行编码的方式很奇怪。 为什么不使用Bitmasks或类似的东西? 除此之外,我认为你的问题根本不相关:比较D访问数据库并做“一些工作”你的支票根本不重要。
使用Contains()函数是一个选项。 我不知道它与索引的表现如何,但它是一个选项:
string userCode = "B";
string someStringToSearchIn = "Current user is: B";
if (someStringToSearchIn.Contains(userCode))
{
//do something
}
首先,我不确定你为何关注这里的效率。 您正在执行极短的字符串搜索,这不太可能降低性能。
话虽如此,我实际上发现这种风格令人困惑。 如果你想知道userCode
是否是“A”和“C”之一, userCode
这样说:
if (userCode.Equals("A") || userCode.Equals("C"))
{
// Do something useful
}
晶莹剔透,也很有效。
作为旁注,如果您可以将这些代码转换为enum
,那么事情可能会更容易:
[Flags]
public enum UserCode
{
None = 0,
A = 1,
B = 2,
C = 4
}
现在你可以说:
if ((userCode & (UserCode.A | UserCode.C)) != UserCode.None)
{
// Do something even more useful
}
至少在我的计算机上, Contains
string
(而不是char
)是最快的。
结果:
IndexOf时间:616ms
包含时间:499ms
包含char时间:707ms
码:
static void Main(string[] args)
{
string userCode = "B";
char userCodeChar = 'B';
int iterations = 10000000;
var sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".IndexOf(userCode) >= 0)
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("IndexOf time: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".Contains(userCode))
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("Contains time: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
if ("AC".Contains(userCodeChar))
{
int a = 1 + 1;
}
}
sw.Stop();
Console.WriteLine("Contains char time: {0}ms", sw.ElapsedMilliseconds);
Console.WriteLine("Done");
Console.ReadLine();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.