web-dev-qa-db-ja.com

文字列の最初の文字を削除する最速の方法

次のような文字列があるとします。

string data= "/temp string";

最初の文字/を削除したい場合は、次のような多くの方法で実行できます。

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

しかし、実際には、どれが最善のアルゴリズムを持っているのか、そしてそれをより速く実行するのかわかりません。
一番良いのはありますか、それとも全部同じですか?

176
Amr Badawy

2番目のオプションは実際には他のオプションと同じではありません-文字列が「/// foo」の場合、「// foo」ではなく「foo」になります。

最初のオプションを理解するには、3番目のオプションよりも少し多くの作業が必要です-Substringオプションを最も一般的で読みやすいと見なします。

(明らかに、個々のステートメントとしてのそれぞれは、何の役に立つこともしません-結果を変数、おそらくdataに割り当てる必要があります。)

実際に問題にならない限り、ここではパフォーマンスを考慮しません。その場合、唯一の方法はテストケースを用意することです。その後、各オプションに対してテストケースを実行するのは簡単です。結果を比較します。私はSubstringがおそらく最初の入力の単一のチャンクから常に文字列を作成することになるので、Substringはおそらくここで最速になると思いますが、Removeは少なくとも潜在的に開始チャンクと終了チャンクを接着します。

130
Jon Skeet

Removename__とSubstringname__はどちらも文字列の固定サイズの部分をスラップアップするのに対して、TrimStartname__は左からスキャンして各文字をテストしてから、まったく同じように実行する必要があるためです。他の2つの方法として働きます。真剣に、しかし、これは髪を分割しています。

8
Marcelo Cantos

あなたが本当に気にかけていれば、あなたはそれをプロファイルすることができます。何度も繰り返すループを書いて、何が起こるか見てください。ただし、これがアプリケーションのボトルネックにならない可能性があり、TrimStartが最も意味的に正しいと思われます。最適化する前にコードを読みやすくするようにしてください。

6
Stefan Kendall

これは超最適化の土地であることは知っていますが、BenchmarkDotNetの車輪を蹴るのは良い言い訳のように思えました。このテストの結果(.NET Coreでも)は、SubstringRemoveよりもわずかに高速です。このサンプルテストでは、Removeの19.37ns対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 |
5