문자열에서 첫 번째 문자를 제거하는 가장 빠른 방법


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
나는 호출에 의해 현재 90,000,000에 대한 각 하나를 확인 할 나는 다음과 같은 결과를 이동 : 제거 : 06.63 - TrimStart : 04.71 - 문자열 : 03.09 그렇게 결과 문자열에서 최고입니다
아 므르 Badawy

5
이 방법으로 성능을 테스트 할 때는 CPU 캐싱의 영향을 받기 때문에 임의 문자열에서 수행해야하며, 배열 (목록)을 미리 채우고 해당 배열의 요소를 임의로 선택해야합니다 ( 명부).
ajeh

12

나는 이것이 극도로 최적화 된 땅이라는 것을 알고 있지만의 바퀴를 치는 좋은 변명처럼 보였습니다 BenchmarkDotNet. 이 테스트의 결과 (.NET Core에서도)는 이 샘플 테스트에서 19.37ns 대 22.52ns Substring보다 훨씬 약간 빠릅니다 . 따라서 ~ 16 % 더 빠릅니다.RemoveRemove

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하기 때문에 보다 빠릅니다 . RemoveSubstring
Jaroslav Jandek

@Jaroslav : 이것은 사실이 아닙니다. 모두 SubstringRemove, 개인 방법에 의존한다 FillSubstring.
Marcelo Cantos

그것을 확인하지는 않았지만 그럴듯하게 들립니다.string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
Dykam

1
@Jaroslav : 상당히 전통적인 Windows 개발 환경에서 mscorlib.dll의 두 가지 방법 중 Reflector 분해를 쳐다보고 있습니다. 둘 다 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.