Самый быстрый способ удалить первый символ в строке

207

Скажем, у нас есть следующая строка

string data= "/temp string";

Если мы хотим удалить первый символ, /мы можем сделать это несколькими способами:

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

Но, на самом деле, я не знаю, какой из них имеет лучший алгоритм и делает это быстрее ...
Есть один, который лучше или все одинаковы?

Амр Бадави
источник
Вы хотите удалить первый символ в любом случае, или вам нужно проверить, действительно ли этот символ /?
SRKX
5
TrimStartне удалит первый символ, он удалит nсимволы с самого начала. Substringсамый быстрый
Ярослав Яндек
мне просто нужно удалить любого первого персонажа
Амр Бадави
6
Если вы удаляете любого первого персонажа, TrimStart()это полностью исключено.
BoltClock
@BoltClock: да, это то, что я сказал (напечатал).
Ярослав Яндек

Ответы:

147

Второй вариант на самом деле не такой, как другие - если строка "/// foo", она станет "foo" вместо "// foo".

Для первого варианта требуется немного больше работы, чем для третьего - я бы посчитал этот Substringвариант наиболее распространенным и читаемым.

(Очевидно, что каждый из них как отдельный оператор не будет делать ничего полезного - вам нужно будет присвоить результат переменной, возможно, dataсамому себе.)

Я бы не стал принимать во внимание производительность, если только это на самом деле не стало для вас проблемой - в этом случае единственный способ, которым вы знали бы, это иметь тестовые случаи, а затем легко запустить эти тестовые примеры для каждого варианта и сравнить результаты. Я бы, Substringвероятно, предположил, что он будет самым быстрым здесь, просто потому, что Substringвсегда заканчивает тем, что создает строку из одного фрагмента исходного ввода, тогда как Removeдолжен, по крайней мере, потенциально склеить начальный блок и конечный блок.

Джон Скит
источник
36
Теперь я проверяю каждого по телефону 90000000 и получаю следующий результат: Remove: 06.63 - TrimStart: 04.71 - subString: 03.09, поэтому из подстроки результата лучше всего
Amr Badawy
5
Просто помните, что, когда вы тестируете производительность таким образом, на вас влияет кэширование процессора, поэтому вы должны сделать это для случайных строк, которыми вы предварительно заполнили массив (список), и случайным образом выбрать элемент этого массива ( список).
9.09.16
12

Я знаю, что это гипероптимизация, но мне показалось, что это хороший повод, чтобы пнуть колеса BenchmarkDotNet. Результат этого теста (даже на .NET Core) Substringнемного быстрее, чем Removeв этом тесте: 19,37 нс против 22,52 нс для 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.
Ярослав Яндек
@ Ярослав: Это не правда. И то Substringи другое Removeполагается на частный метод FillSubstring.
Марсело Кантос
Не string Remove(this string source, int from, int to) { return source.SubString(0, from) + source.SubString(to); }
проверял
1
@Jaroslav: я смотрю на разборку Reflector двух методов в mscorlib.dll в довольно обычной среде разработки для Windows. Они оба вызывают System.PInvoke.EE.AllocateStringвыделение целевого строкового объекта, а затем вызывают FillSubstringкопирование символов. Я смотрю не на ту вещь?
Марсело Кантос
1
@Marcelo: Во всяком случае, ваш первый комментарий изначально говорил совсем другое. Вероятно, мне следовало бы использовать лучшую формулировку, хотя суть верна ( Substring> Remove). Я не буду комментировать дальше, потому что обсуждение заняло достаточно времени.
Ярослав Яндек
6

Вы могли бы профилировать это, если вы действительно заботились. Напишите цикл из множества итераций и посмотрите, что произойдет. Однако есть вероятность, что это не является узким местом в вашем приложении, и TrimStart кажется наиболее семантически правильным. Стремитесь писать код читабельно, прежде чем оптимизировать.

Стефан Кендалл
источник
6
TrimStartнаименее правильно, так "//temp string".TrimStart('/')как не просто удалит первый '/'.
Марсело Кантос
Функция плохо названа тогда. Я не парень C #.
Стефан Кендалл
@StefanKendall: Посмотрите на теги
Виджай Сингх Рана