Cara tercepat untuk menghapus karakter pertama dalam sebuah String

207

Katakanlah kita memiliki string berikut

string data= "/temp string";

Jika kita ingin menghapus karakter pertama yang /bisa kita lakukan dengan banyak cara seperti:

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

Tapi, sungguh saya tidak tahu mana yang memiliki algoritma terbaik dan melakukan itu lebih cepat ..
Apakah ada yang terbaik atau semuanya sama?

Amr Badawy
sumber
Apakah Anda ingin menghapus karakter pertama atau Anda perlu memeriksa bahwa karakter ini memang merupakan /?
SRKX
5
TrimStarttidak akan menghapus karakter pertama, itu akan menghapus nkarakter dari awal. Substringadalah yang tercepat.
Jaroslav Jandek
saya hanya perlu menghapus karakter pertama
Amr Badawy
6
Jika Anda menghapus karakter pertama, TrimStart()sama sekali tidak ada pertanyaan.
BoltClock
@BoltClock: yeah, itu yang saya katakan (ketikkan).
Jaroslav Jandek

Jawaban:

147

Opsi kedua benar-benar tidak sama dengan yang lain - jika string "/// foo" itu akan menjadi "foo", bukan "// foo".

Opsi pertama perlu sedikit lebih banyak pekerjaan untuk dipahami daripada yang ketiga - Saya akan melihat Substringopsi sebagai yang paling umum dan dapat dibaca.

(Tentunya masing-masing sebagai pernyataan individu tidak akan melakukan apa pun yang berguna - Anda harus menetapkan hasilnya ke variabel, mungkin dataitu sendiri.)

Saya tidak akan mempertimbangkan kinerja di sini kecuali jika itu benar-benar menjadi masalah bagi Anda - dalam hal ini satu-satunya cara Anda akan tahu untuk memiliki kasus uji, dan kemudian mudah untuk menjalankan kasus uji tersebut untuk setiap opsi dan bandingkan hasilnya. Saya berharap Substringmungkin menjadi yang tercepat di sini, hanya karena Substringselalu berakhir dengan membuat string dari satu potong input asli, sedangkan Removesetidaknya harus berpotensi menyatukan potongan awal dan bagian akhir.

Jon Skeet
sumber
36
Saya memeriksa sekarang dengan menelepon masing-masing sekitar 90000000 dan saya pergi hasil berikut: Hapus: 06.63 - TrimStart: 04.71 - subString: 03.09 jadi dari hasil substring adalah yang terbaik
Amr Badawy
5
Hanya ingat bahwa ketika Anda menguji kinerja dengan cara ini, Anda dipengaruhi oleh caching CPU, jadi Anda perlu melakukannya pada string acak, bahwa Anda mempopulasikan array (daftar) dengan, dan secara acak memilih elemen array itu ( daftar).
ajeh
12

Saya tahu ini adalah hiper-optimasi tanah, tetapi sepertinya alasan yang bagus untuk menendang roda BenchmarkDotNet. Hasil tes ini (pada .NET Core) adalah yang Substringsedikit lebih cepat daripada Remove, dalam tes sampel ini: 19.37ns vs 22.52ns untuk Remove. Jadi beberapa ~ 16% lebih cepat.

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>();
        }
    }
}

Hasil:

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 |
Nicholas Petersen
sumber
9

Saya kira itu Removedan Substringakan mengikat untuk tempat pertama, karena mereka berdua menyeruput bagian ukuran tetap dari string, sedangkan TrimStartmelakukan scan dari kiri dengan tes pada setiap karakter dan kemudian harus melakukan pekerjaan yang persis sama dengan dua metode lainnya. Serius, meskipun, ini adalah rambut yang membelah.

Marcelo Cantos
sumber
1
Sebenarnya, Substringlebih cepat daripada Remove, karena Removepanggilan Substring.
Jaroslav Jandek
@ Jaroslav: Ini tidak benar. Keduanya Substringdan Removemengandalkan metode pribadi FillSubstring,.
Marcelo Cantos
Tidak memverifikasinya, tetapi kedengarannya sangat masuk akal:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam
1
@ Jaroslav: Saya sedang menatap Reflector pembongkaran dua metode di mscorlib.dll pada lingkungan dev Windows yang cukup konvensional. Mereka berdua memanggil System.PInvoke.EE.AllocateStringuntuk mengalokasikan objek string tujuan dan kemudian panggilan FillSubstringuntuk menyalin karakter. Apakah saya melihat hal yang salah?
Marcelo Cantos
1
@ Marscelo: Pokoknya, komentar pertama Anda awalnya mengatakan hal yang sama sekali berbeda. Saya mungkin harus menggunakan kata-kata yang lebih baik, intinya valid meskipun ( Substring> Remove). Saya tidak akan berkomentar lebih jauh karena pembahasannya cukup lama.
Jaroslav Jandek
6

Anda dapat membuatnya, jika Anda benar-benar peduli. Tulis satu lingkaran banyak iterasi dan lihat apa yang terjadi. Namun, ada kemungkinan bahwa ini bukan hambatan dalam aplikasi Anda, dan TrimStart tampaknya yang paling benar secara semantik. Berusaha untuk menulis kode dengan mudah sebelum mengoptimalkan.

Stefan Kendall
sumber
6
TrimStartadalah yang paling benar, karena tidak"//temp string".TrimStart('/') akan hanya menghapus yang pertama . '/'
Marcelo Cantos
Nama fungsi itu buruk. Saya bukan orang C #.
Stefan Kendall
@StefanKendall: Lihat tag
Vijay Singh Rana