วิธีที่เร็วที่สุดในการลบอักขระตัวแรกใน String


207

สมมติว่าเรามีสตริงต่อไปนี้

string data= "/temp string";

หากเราต้องการลบตัวอักษรตัวแรก/เราสามารถทำได้หลายวิธีเช่น:

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

แต่จริงๆฉันไม่รู้ว่าอันไหนมีอัลกอริธึมที่ดีที่สุดและทำได้เร็วขึ้น ..
มีอันไหนที่ดีที่สุดหรือเหมือนกันทั้งหมด


คุณต้องการลบอักขระตัวแรกออกไปหรือคุณต้องการตรวจสอบว่าตัวละครนี้เป็นตัวจริง/หรือไม่?
SRKX

5
TrimStartจะไม่ลบอักขระตัวแรกมันจะลบnตัวอักษรออกจากจุดเริ่มต้น Substringเร็วที่สุด
Jaroslav Jandek

ฉันแค่ต้องลบตัวละครตัวแรกออก
Amr Badawy

6
หากคุณลบตัวอักษรตัวแรกTrimStart()ออกจากคำถามอย่างสมบูรณ์
BoltClock

@BoltClock: ใช่นั่นคือสิ่งที่ฉันพูด (พิมพ์)
Jaroslav Jandek

คำตอบ:


147

ตัวเลือกที่สองนั้นไม่เหมือนกันกับตัวอื่น ๆ - ถ้าสตริงเป็น "/// foo" มันจะกลายเป็น "foo" แทน "// foo"

ตัวเลือกแรกต้องใช้งานมากกว่านี้เพื่อทำความเข้าใจมากกว่าตัวเลือกที่สาม - ฉันจะดูSubstringตัวเลือกว่าเป็นวิธีที่ใช้กันทั่วไปและสามารถอ่านได้

(เห็นได้ชัดว่าพวกเขาแต่ละคนในฐานะแถลงส่วนตัวจะไม่ทำสิ่งที่มีประโยชน์ - คุณจะต้องกำหนดผลลัพธ์ให้กับตัวแปรซึ่งอาจเป็นไปได้dataเอง)

ฉันจะไม่คำนึงถึงประสิทธิภาพการทำงานที่นี่เว้นแต่ว่ามันจะกลายเป็นปัญหาสำหรับคุณ - ในกรณีนี้วิธีเดียวที่คุณรู้ว่าจะมีกรณีทดสอบและจากนั้นมันง่ายมากที่จะเรียกใช้กรณีทดสอบเหล่านั้นสำหรับแต่ละตัวเลือกและ เปรียบเทียบผลลัพธ์ ฉันคาดหวังว่าSubstringอาจจะเร็วที่สุดที่นี่เพียงเพราะSubstringจบลงด้วยการสร้างสตริงจากอันเดียวของอินพุตดั้งเดิมในขณะRemoveที่อย่างน้อยก็อาจติดกาวเข้าด้วยกันเป็นชิ้นเริ่มและส่วนท้าย


36
ฉันจะตรวจสอบตอนนี้โดยเรียกแต่ละคนเกี่ยวกับ 90000000 และฉันไปผลลัพธ์ดังต่อไปนี้: ลบ: 06.63 - TrimStart: 04.71 - subString: 03.09 ดังนั้นจากสตริงย่อยผลที่ดีที่สุด
Amr Badawy

5
เพียงจำไว้ว่าเมื่อคุณทำการทดสอบประสิทธิภาพด้วยวิธีนี้คุณจะได้รับผลกระทบจากการแคช CPU ดังนั้นคุณต้องทำเช่นนั้นกับสตริงแบบสุ่มที่คุณเติมอาร์เรย์ (รายการ) ไว้ล่วงหน้าด้วยและเลือกองค์ประกอบของอาร์เรย์นั้นแบบสุ่ม ( รายการ).
ajeh

12

ฉันรู้ว่านี้เป็นดินแดนไฮเปอร์เพิ่มประสิทธิภาพ BenchmarkDotNetแต่มันดูเหมือนจะเป็นข้อแก้ตัวที่ดีที่จะเตะล้อของ ผลของการทดสอบนี้ (ใน .NET หลักแม้) คือว่าSubstringเป็นเคยดังนั้นเล็กน้อยเร็วกว่าRemoveในการทดสอบตัวอย่างนี้: 19.37ns VS 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

@Jaroslav: นี่ไม่เป็นความจริง ทั้งสองSubstringและRemoveใช้วิธีการแบบส่วนตัว, FillSubstring.
Marcelo Cantos

ไม่ได้ตรวจสอบ แต่ฟังดูน่าเชื่อถือมาก:string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam

1
@Jaroslav: ฉันกำลังจ้องมองที่ถอดแยกชิ้นส่วนของสองวิธีใน mscorlib.dll ในสภาพแวดล้อมที่เป็นธรรม Windows dev ธรรมดา พวกเขาทั้งสองเรียกSystem.PInvoke.EE.AllocateStringการจัดสรรวัตถุสตริงปลายทางแล้วโทรFillSubstringเพื่อคัดลอกอักขระข้าม ฉันกำลังดูสิ่งผิดปกติหรือไม่?
Marcelo Cantos

1
@Marcelo: อย่างไรก็ตามความคิดเห็นแรกของคุณในตอนแรกพูดถึงสิ่งที่แตกต่างอย่างสิ้นเชิง ฉันควรจะใช้ถ้อยคำที่ดีกว่านี้จุดนี้ใช้ได้แม้ว่า ( Substring> Remove) ฉันจะไม่แสดงความคิดเห็นเพิ่มเติมเพราะการอภิปรายใช้เวลาของฉันมากพอ
Jaroslav Jandek

6

คุณสามารถโปรไฟล์ได้ถ้าคุณใส่ใจจริงๆ เขียนวนซ้ำหลายรอบแล้วดูว่าเกิดอะไรขึ้น อย่างไรก็ตามโอกาสที่ว่านี้ไม่ได้เป็นคอขวดในใบสมัครของคุณและ TrimStart ดูเหมือนว่าถูกต้องทางความหมายมากที่สุด พยายามเขียนโค้ดให้อ่านก่อนที่จะปรับให้เหมาะสม


6
TrimStartเป็นอย่างน้อยที่ถูกต้องเนื่องจาก"//temp string".TrimStart('/')จะไม่เพียง '/'แต่เอาคนแรก
Marcelo Cantos

ฟังก์ชั่นตั้งชื่อได้ไม่ดีแล้ว ฉันไม่ใช่คน C #
Stefan Kendall

@StefanKendall: ดูแท็ก
Vijay Singh Rana
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.