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


207

次の文字列があるとします

string data= "/temp string";

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

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

しかし、実際にどれが最良のアルゴリズムを持っているのかわからないので、それをより速く実行します。
最高のもの、またはすべてが同じものはありますか?


とにかく最初の文字を削除しますか、またはこの文字が本当にaであることを確認する必要があり/ますか?
SRKX 2010

5
TrimStart最初の文字は削除されませんn。最初から文字が削除されます。Substring最速です。
Jaroslav Jandek、2010

私は最初の文字を削除するだけです
Amr Badawy 2010

6
最初の文字を削除する場合TrimStart()は、完全に問題外です。
BoltClock

@BoltClock:ええ、それは私が言った(タイプした)ものです。
Jaroslav Jandek、2010

回答:


147

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

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

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

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


36
私は今度はそれぞれ90000000を呼び出してチェックし、次の結果に行きます:削除:06.63-TrimStart:04.71-subString:03.09したがって、結果からサブストリングが最良です
Amr Badawy

5
この方法でパフォーマンスをテストすると、CPUキャッシュの影響を受けるので、配列(リスト)に事前に値を入力し、その配列の要素(リスト)。
ajeh 16

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

私は推測したいRemoveSubstringのに対し、彼ら以来、最初の場所のための文字列の固定サイズの部分まで両方の吸い込みを結ぶだろうTrimStart各文字のテストで左からスキャンを行い、その後、まったく同じ作業を実行する必要があります他の2つの方法。真剣に、しかし、これは髪を分割しています。


1
実際にSubstringRemove、がをRemove呼び出すため、よりも高速ですSubstring
Jaroslav Jandek、2010

@Jaroslav:これは真実ではありません。両方SubstringRemove、民間の方法に依存していますFillSubstring
Marcelo Cantos、2010

確認できませんでしたが、もっともらしいようです:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam 2010

1
@Jaroslav:私はかなり一般的なWindows開発環境でmscorlib.dllの2つのメソッドのReflector逆アセンブリを凝視しています。どちらも呼び出しSystem.PInvoke.EE.AllocateStringて宛先文字列オブジェクトを割り当て、次にを呼び出しFillSubstringて文字をコピーします。私は間違ったものを見ていますか?
Marcelo Cantos、2010

1
@マルセロ:とにかく、あなたの最初のコメントはもともとまったく違うことを言っていました。私はおそらくもっと良い言い回しを使うべきでしたが、ポイントは有効です(Substring> Remove)。十分な議論があったため、これ以上コメントすることはしません。
Jaroslav Jandek 2010

6

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


6
TrimStartは、最初のを削除するだけで"//temp string".TrimStart('/')ないため、最も正確ではありません'/'
Marcelo Cantos、2010

そのとき、関数の名前は不十分です。私はC#の人ではありません。
Stefan Kendall、

@StefanKendall:タグを見
ビジェイ・シンラナ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.