【问题标题】:Fastest way to remove first char in a String删除字符串中第一个字符的最快方法
【发布时间】:2011-03-14 10:07:25
【问题描述】:

假设我们有以下字符串

string data= "/temp string";

如果我们想删除第一个字符/,我们可以通过很多方法来完成,例如:

data.Remove(0,1);
data.TrimStart('/');
data.Substring(1);

但是,我真的不知道哪一个拥有最好的算法并且做得更快..
有没有一个是最好的,或者所有的都是一样的?

【问题讨论】:

  • 您还是要删除第一个字符还是需要检查该字符是否确实是/
  • TrimStart 不会删除第一个字符,它会从开头删除 n 字符。 Substring 最快。
  • 我只需要删除任何第一个字符
  • 如果您要删除任何第一个字符,TrimStart() 完全不可能。
  • @BoltClock:是的,这就是我所说的(输入)。

标签: c# string substring performance trim


【解决方案1】:

我知道这是超优化领域,但这似乎是一个很好的借口来踢BenchmarkDotNet 的车轮。此测试的结果(甚至在 .NET Core 上)是 SubstringRemove 稍微快一点,在此示例测试中:19.37ns 与 Remove 的 22.52ns。所以大约快 16%。

using System;
using BenchmarkDotNet.Attributes;

namespace BenchmarkFun
{
    public class StringSubstringVsRemove
    {
        public readonly string SampleString = " My name is Daffy Duck.";

        [Benchmark]
        public string StringSubstring() => SampleString.Substring(1);

        [Benchmark]
        public string StringRemove() => SampleString.Remove(0, 1);

        public void AssertTestIsValid()
        {
            string subsRes = StringSubstring();
            string remvRes = StringRemove();

            if (subsRes == null
                || subsRes.Length != SampleString.Length - 1
                || subsRes != remvRes) {
                throw new Exception("INVALID TEST!");
            }
        }
    }

    class Program
    {
        static void Main()
        {
            // let's make sure test results are really equal / valid
            new StringSubstringVsRemove().AssertTestIsValid();

            var summary = BenchmarkRunner.Run<StringSubstringVsRemove>();
        }
    }
}

结果:

BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17763.253 (1809/October2018Update/Redstone5)
Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview-010184
  [Host]     : .NET Core 3.0.0-preview-27324-5 (CoreCLR 4.6.27322.0, CoreFX 4.7.19.7311), 64bit RyuJIT
  DefaultJob : .NET Core 3.0.0-preview-27324-5 (CoreCLR 4.6.27322.0, CoreFX 4.7.19.7311), 64bit RyuJIT

|          Method |     Mean |     Error |    StdDev |
|---------------- |---------:|----------:|----------:|
| StringSubstring | 19.37 ns | 0.3940 ns | 0.3493 ns |
|    StringRemove | 22.52 ns | 0.4062 ns | 0.3601 ns |

【讨论】:

    【解决方案2】:

    第二个选项确实和其他选项不一样——如果字符串是“///foo”,它将变成“foo”而不是“//foo”。

    第一个选项比第三个需要更多的工作来理解 - 我认为Substring 选项是最常见和可读的。

    (显然,它们中的每一个作为单独的语句都不会做任何有用的事情 - 您需要将结果分配给一个变量,可能是 data 本身。)

    我不会在这里考虑性能,除非它实际上对您来说是个问题 - 在这种情况下,您知道的唯一方法就是拥有测试用例,然后运行这些测试用例很容易每个选项并比较结果。我希望Substring 可能是这里最快的,因为Substring 总是最终从原始输入的单个块创建一个字符串,而Remove 必须至少可能将起始块和结束块粘合在一起。

    【讨论】:

    • 我现在通过调用每个约 90000000 进行检查,我得到以下结果:删除:06.63 - TrimStart:04.71 - subString:03.09 所以从结果子字符串中是最好的
    • 请记住,当您以这种方式测试性能时,您会受到 CPU 缓存的影响,因此您需要在随机字符串上执行此操作,您预先填充了一个数组(列表),并且随机选择该数组(列表)的元素。
    【解决方案3】:

    我猜RemoveSubstring 会并列第一,因为它们都吞食了字符串的固定大小部分,而TrimStart 从左侧进行扫描,每个都进行测试然后必须执行与其他两种方法完全相同的工作。不过,说真的,这简直让人毛骨悚然。

    【讨论】:

    • 其实SubstringRemove快,因为Remove调用Substring
    • @Jaroslav:这不是真的。 SubstringRemove 都依赖于私有方法 FillSubstring
    • 没有验证,但听起来很有道理:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
    • @Jaroslav:我在一个相当传统的 Windows 开发环境中盯着 mscorlib.dll 中两种方法的 Reflector 反汇编。他们都调用System.PInvoke.EE.AllocateString 来分配目标字符串对象,然后调用FillSubstring 来复制字符。我看错了吗?
    • @Marcelo:无论如何,你的第一条评论最初说的是完全不同的东西。我可能应该使用更好的措辞,但这一点是有效的(Substring > Remove)。我不打算进一步评论,因为讨论花了我足够的时间。
    【解决方案4】:

    如果您真的关心,您可以对其进行分析。编写一个包含许多迭代的循环,看看会发生什么。然而,这可能不是您的应用程序的瓶颈,而 TrimStart 似乎在语义上最正确。在优化之前努力编写可读的代码。

    【讨论】:

    • TrimStart 是最不正确的,因为"//temp string".TrimStart('/')不会仅删除第一个'/'
    • 这个函数的名字很糟糕。我不是 C# 人。
    • @StefanKendall:看看标签
    猜你喜欢
    • 1970-01-01
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    • 2011-04-11
    • 1970-01-01
    • 2012-04-25
    相关资源
    最近更新 更多