繁体   English   中英

这是搜索子字符串的最有效方法吗?

[英]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次迭代:

  • 包含(值) - 耗时130毫秒
  • IndexOf(value,StringComparison.Ordinal) - 耗时128毫秒

所以你可以看到,非常非常接近。 再一次,使用更可维护的东西。

更新2 :如果您的代码始终是单个char(不是1-char字符串),则IndexOf()更快:

  • 包含(char值) - 耗时94毫秒
  • IndexOf(char值) - 花了16毫秒

如果你知道你的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM