删除字符串中第一个字符的最快方法


207

说我们有以下字符串

string data= "/temp string";

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

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

但是,我真的不知道哪一个具有最好的算法,做更快..
是否有一个最好的,或者都是一样的吗?


您是否要删除第一个字符,还是需要检查该字符确实是一个/
SRKX'7

5
TrimStart不会删除第一个字符,而是n从头开始删除字符。Substring是最快的。
Jaroslav Jandek

我只需要删除第一个字符
Amr Badawy,2010年

6
如果要删除任何第一个字符,TrimStart()则完全不可能。
BoltClock

@BoltClock:是的,这就是我说的(输入的)。
Jaroslav Jandek'7

Answers:


147

第二个选项确实与其他选项不同-如果字符串为“ /// foo”,它将变为“ foo”而不是“ // foo”。

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

(显然,将它们中的每一个作为单独的语句都无济于事-您需要将结果分配给变量,可能是变量data本身。)

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


36
我现在通过调用每个大约9000万来检查,然后得到以下结果:删除:06.63-TrimStart:04.71-subString:03.09所以从结果中来看,子字符串是最好的
Amr Badawy 2010年

5
请记住,以这种方式测试性能时,您会受到CPU缓存的影响,因此您需要对随机字符串执行此操作,并使用数组预先填充一个数组(列表),然后随机选择该数组的元素(清单)。
ajeh

12

我知道这是过度优化的领域,但这似乎是一个很好的借口BenchmarkDotNet。该测试的结果(甚至在.NET Core上)SubstringRemove在此示例测试中要快得多:分别为19.37ns和22.52ns Remove。所以快约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 |

9

我猜想,Remove并且Substring将并列第一,因为他们都啜食了绳子的固定大小的部分,而TrimStart不会从左侧与每个字符的测试扫描,然后必须执行完全相同的工作为其他两种方法。严重的是,这真是一头雾水。


1
其实,Substring比速度更快Remove,因为Remove电话Substring
Jaroslav Jandek 2010年

@贾罗斯拉夫:这是不正确的。双方SubstringRemove依赖于一个私有方法,FillSubstring
马塞洛·坎托斯

没有验证它,但这听起来似乎很合理:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam,2010年

1
@Jaroslav:我盯着在相当传统的Windows开发环境中mscorlib.dll中的两种方法的Reflector反汇编。它们都调用System.PInvoke.EE.AllocateString以分配目标字符串对象,然后调用FillSubstring以复制字符。我在看错东西吗?
马塞洛·坎托斯

1
@Marcelo:无论如何,您的第一条评论原本是完全不同的话。我可能应该使用更好的措辞,尽管这一点是有效的(Substring> Remove)。我将不做进一步评论,因为讨论花费了我很多时间。
Jaroslav Jandek'7

6

如果您真的很在意,可以进行配置。编写一个包含许多迭代的循环,看看会发生什么。但是,这可能不是您应用程序中的瓶颈,并且TrimStart似乎在语义上是最正确的。在优化之前,力求以可读的方式编写代码。


6
TrimStart是最正确的,因为"//temp string".TrimStart('/')只是删除了第一'/'
Marcelo Cantos 2010年

然后,该函数的命名不正确。我不是C#家伙。
Stefan Kendall

@StefanKendall:看一下标签
Vijay Singh Rana
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.