Cách nhanh nhất để loại bỏ char đầu tiên trong Chuỗi


206

Nói rằng chúng ta có chuỗi sau đây

string data= "/temp string";

Nếu chúng ta muốn xóa ký tự đầu tiên, /chúng ta có thể thực hiện bằng nhiều cách như:

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

Nhưng, thực sự tôi không biết cái nào có thuật toán tốt nhất và làm điều đó nhanh hơn ..
Có cái nào là tốt nhất hay tất cả đều giống nhau không?


Bạn có muốn xóa ký tự đầu tiên không hoặc bạn cần kiểm tra xem ký tự này có thực sự là a /không?
SRKX

5
TrimStartSẽ không xóa char đầu tiên, nó sẽ xóa nký tự từ đầu. Substringlà nhanh nhất
Jaroslav Jandek

tôi chỉ cần xóa bất kỳ ký tự đầu tiên
Amr Badawy

6
Nếu bạn loại bỏ bất kỳ ký tự đầu tiên, TrimStart()hoàn toàn không có vấn đề.
BoltClock

@BoltClock: yeah, đó là những gì tôi đã nói (đánh máy).
Jaroslav Jandek

Câu trả lời:


146

Tùy chọn thứ hai thực sự không giống với các tùy chọn khác - nếu chuỗi là "/// foo", nó sẽ trở thành "foo" thay vì "// foo".

Tùy chọn đầu tiên cần nhiều công việc hơn để hiểu hơn thứ ba - tôi sẽ xem Substringtùy chọn này là phổ biến nhất và dễ đọc hơn.

(Rõ ràng mỗi người trong số họ như một tuyên bố riêng lẻ sẽ không làm gì hữu ích - bạn sẽ cần gán kết quả cho một biến, có thể là datachính nó.)

Tôi sẽ không xem xét hiệu suất ở đây trừ khi nó thực sự trở thành vấn đề với bạn - trong trường hợp đó, cách duy nhất bạn biết là có các trường hợp thử nghiệm, và sau đó thật dễ dàng để chạy các trường hợp thử nghiệm đó cho mỗi tùy chọn và so sánh kết quả. Tôi hy vọng Substringcó thể là nhanh nhất ở đây, đơn giản là vì Substringluôn luôn tạo ra một chuỗi từ một đoạn đầu vào ban đầu, trong khi Removeít nhất phải có khả năng kết dính một đoạn bắt đầu và đoạn kết thúc.


35
Tôi kiểm tra ngay bây giờ bằng cách gọi cho mỗi người khoảng 90000000 và tôi đi theo kết quả sau: Xóa: 06.63 - TrimStart: 04.71 - subString: 03.09 vì vậy, chuỗi con kết quả là tốt nhất
Amr Badawy

5
Chỉ cần nhớ rằng khi bạn đang kiểm tra hiệu năng theo cách này, bạn sẽ bị ảnh hưởng bởi bộ nhớ đệm CPU, do đó bạn cần thực hiện điều đó trên các chuỗi ngẫu nhiên, bạn đã điền trước một mảng (danh sách) và chọn ngẫu nhiên phần tử của mảng đó ( danh sách).
ajeh

12

Tôi biết đây là vùng đất siêu tối ưu hóa, nhưng có vẻ như là một cái cớ tốt để đá các bánh xe BenchmarkDotNet. Kết quả của bài kiểm tra này (trên .NET Core chẵn) là Substringnhanh hơn một chút so với Remove, trong bài kiểm tra mẫu này: 19,37ns so với 22,52ns cho Remove. Vì vậy, một số nhanh hơn ~ 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>();
        }
    }
}

Các kết quả:

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

Tôi đoán điều đó RemoveSubstringsẽ buộc ở vị trí đầu tiên, vì cả hai đều nhét một phần kích thước cố định của chuỗi, trong khi TrimStartquét từ bên trái với một bài kiểm tra trên mỗi ký tự và sau đó phải thực hiện chính xác cùng một công việc như hai phương pháp khác. Nghiêm túc, mặc dù, đây là chia tóc.


1
Trên thực tế, Substringlà nhanh hơn Remove, bởi vì Removecác cuộc gọi Substring.
Jaroslav Jandek

@Jar Tư: Điều này không đúng. Cả hai SubstringRemovedựa vào một phương pháp riêng tư FillSubstring.
Marcelo Cantos

Không xác minh nó, nhưng nó có vẻ rất hợp lý:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam

1
@Jar Tư: Tôi đang nhìn chằm chằm vào sự phân tách Reflector của hai phương thức trong mscorlib.dll trên môi trường phát triển Windows khá thông thường. Cả hai đều gọi System.PInvoke.EE.AllocateStringđể phân bổ đối tượng chuỗi đích và sau đó gọi FillSubstringđể sao chép các ký tự trên. Tôi đang nhìn vào điều sai?
Marcelo Cantos

1
@Marcelo: Dù sao, bình luận đầu tiên của bạn ban đầu đã nói lên một điều hoàn toàn khác. Tôi có lẽ nên sử dụng một từ ngữ tốt hơn, điểm này là hợp lệ mặc dù ( Substring> Remove). Tôi sẽ không bình luận gì thêm vì cuộc thảo luận đã chiếm đủ thời gian của tôi.
Jaroslav Jandek

6

Bạn có thể hồ sơ nó, nếu bạn thực sự quan tâm. Viết một vòng lặp của nhiều lần lặp và xem điều gì sẽ xảy ra. Tuy nhiên, rất có thể đây không phải là nút cổ chai trong ứng dụng của bạn và TrimStart có vẻ đúng nhất về mặt ngữ nghĩa. Phấn đấu viết mã dễ đọc trước khi tối ưu hóa.


6
TrimStartlà ít chính xác nhất, vì "//temp string".TrimStart('/')sẽ không chỉ loại bỏ cái đầu tiên '/'.
Marcelo Cantos

Các chức năng được đặt tên kém sau đó. Tôi không phải là một anh chàng C #.
Stefan Kendall

@StefanKendall: Xem các thẻ
Vijay Singh Rana
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.