Самый эффективный способ объединения строк?

Каков наиболее эффективный способ объединения строк?

21.08.2008 20:27:15
Я хочу сделать здесь заметное предупреждение о том, что принятый ответ является значительно неполным, поскольку в нем не рассматриваются все соответствующие случаи.
usr 23.06.2016 13:57:31
@usr Действительно ... более подробную информацию о StringBuilderслучаях использования можно найти здесь .
Tamir Vered 26.01.2017 13:00:38
Мой новый фаворит на C # 6 - это $ "Постоянный текст здесь {foo} и {bar}" ... это как String.Formatна стероидах. Который, с точки зрения производительности, немного медленнее на одной линии, чем +и String.Concat, но намного лучше, чем те, хотя и медленнее, чем StringBuilderна нескольких вызовах. Практически говоря, различия в производительности таковы, что, если бы мне пришлось выбирать только один способ объединения, я бы выбрал интерполяцию строк, используя $... Если два пути, то добавьте StringBuilderв свой набор инструментов. С этими двумя способами вы настроены.
u8it 22.09.2017 20:54:37
String.JoinОтвет ниже не делает +справедливость и, практически говоря, плохой путь для конкатенации строк, но это удивительно высокая производительность мудрого. Ответ почему интересно. String.Concatи String.Joinоба могут действовать на массивы, но String.Joinна самом деле быстрее. По-видимому, String.Joinон довольно сложный и более оптимизированный, чем String.Concatчастично, потому что он работает аналогично тому, StringBuilderчто сначала вычисляет длину строки, а затем строит строку, извлекая выгоду из этого знания, используя UnSafeCharBuffer.
u8it 22.09.2017 21:22:40
Итак, это быстро, но String.Joinтакже требует создания массива, который кажется неэффективным с точки зрения ресурсов, верно? ... Получается, +и String.Concatв любом случае строит массивы для их составляющих. Следовательно, создание массива вручную и его подача String.Joinвыполняется сравнительно быстрее ... однако, он по- StringBuilderпрежнему превосходит String.Joinпрактически во всех практических $целях, но лишь немного медленнее и намного быстрее при длинных строках ... не говоря уже о том, что его неудобно и некрасиво использовать, String.Joinесли у вас есть создать массив для него на месте.
u8it 22.09.2017 21:22:44
17 ОТВЕТОВ
РЕШЕНИЕ

Этот StringBuilder.Append()метод намного лучше, чем использование +оператора. Но я обнаружил, что при выполнении 1000 конкатенаций или менее, String.Join()это даже более эффективно, чем StringBuilder.

StringBuilder sb = new StringBuilder();
sb.Append(someString);

Единственная проблема в String.Joinтом, что вам нужно объединить строки с общим разделителем.

Изменить: как указал @ryanversaw , вы можете сделать разделитель string.Empty.

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });
153
22.11.2019 09:07:49
StringBuilderимеет огромную сопоставимую стоимость запуска, он эффективен только при использовании с очень большими строками или очень большим количеством конкатенаций. Это не тривиально, чтобы узнать для любой конкретной ситуации. Если производительность является проблемой, профилирование - ваш друг (проверьте ANTS).
Abel 4.11.2009 13:22:58
Это не так для конкатенации одной строки. Допустим, вы выполняете myString = "foo" + var1 + "bar" + var2 + "hello" + var3 + "world", компилятор автоматически превращает это в вызов string.concat, который настолько эффективен, насколько это возможно. Этот ответ неправильный, есть много лучших ответов на выбор
csauve 12.01.2011 17:56:24
Для тривиальной конкатенации строк используйте то, что когда-либо наиболее читабельно. строка a = b + c + d; почти всегда будет быстрее, чем делать это с StringBuilder, но разница, как правило, не имеет значения. Используйте StringBuilder (или другой вариант по вашему выбору) при многократном добавлении к одной и той же строке (например, создание отчета) или при работе с большими строками.
Swanny 26.06.2011 10:28:56
Почему ты не упомянул string.Concat?
Venemo 27.09.2013 12:56:10

Наиболее эффективным является использование StringBuilder, например так:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy: String.Concat - это хорошо, если у вас есть пара небольших вещей. Но если вы объединяете мегабайты данных, ваша программа, скорее всего, будет работать.

2
21.08.2008 20:28:13
эй, какое решение для мегабайт данных?
Neel 10.03.2016 13:22:35

Для двух строк вы определенно не хотите использовать StringBuilder. Существует некоторый порог, выше которого издержки StringBuilder меньше, чем накладные расходы на выделение нескольких строк.

Итак, для более чем 2-3 строк используйте код DannySmurf . В противном случае просто используйте оператор +.

0
23.05.2017 10:31:19

От Chinh Do - StringBuilder не всегда быстрее :

Эмпирические правила

  • При объединении трех динамических строковых значений или менее используйте традиционную конкатенацию строк.

  • При объединении более трех динамических строковых значений используйте StringBuilder.

  • При построении большой строки из нескольких строковых литералов используйте @строковый литерал или оператор inline +.

Большую часть времени StringBuilderэто ваша лучшая ставка, но в этом посте, как показано в некоторых случаях, вы должны хотя бы подумать о каждой ситуации.

57
22.11.2019 09:04:50
afaik @ отключает только обработку escape-последовательностей. msdn.microsoft.com/en-us/library/362314fe.aspx согласен
abatishchev 18.07.2010 20:11:52

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

0
21.08.2008 20:34:49

Если вы работаете в цикле, StringBuilderвероятно, это путь; это избавляет вас от необходимости регулярно создавать новые строки. Впрочем, в коде, который запускается только один раз, String.Concatэто нормально.

Тем не менее, Рико Мариани (гуру оптимизации .NET) составил тест, в котором он в конце заявил, что в большинстве случаев он рекомендует String.Format.

12
22.11.2019 09:05:36
Я много лет рекомендовал использовать string.format вместо string + string людям, с которыми работал. Я думаю, что преимущества читабельности являются дополнительным преимуществом помимо выигрыша в производительности.
Scott Lawrence 14.11.2008 18:38:38
Это действительно правильный ответ. В настоящее время принятый ответ для StringBuilder является неправильным, поскольку в нем не упоминается добавление в одну строку, для которого string.concat или + быстрее. Малоизвестным фактом является то, что компилятор фактически переводит + в string.concat. Кроме того, для циклов или для многострочных конкатов я использую пользовательский построитель строк, который добавляется только при вызове .ToString - для преодоления неопределенной проблемы с буфером, которая есть у
csauve 12.01.2011 17:53:55
string.Format не самый быстрый способ ни при каких обстоятельствах. Я не знаю, как придумать случай, когда это произойдет.
usr 23.06.2016 13:55:00
@usr - обратите внимание, что Рико явно не говорит, что он самый быстрый , просто это его рекомендация: «Несмотря на то, что это худший результат, и мы заранее знали, что оба ваших архитектора CLR Performance Architects согласны с тем, что [string.Format] должен быть выбором по умолчанию. В очень маловероятном случае, если это станет проблемой перфорирования, эта проблема легко решается с помощью лишь скромных локальных изменений. Обычно вы просто наживаете на хорошей поддержке. "
Adam V 30.04.2018 14:00:51
@ AdamV вопрос о самом быстром способе. Я не согласен с тем, что это выбор по умолчанию, но не по причинам. Это может быть неуклюжий синтаксис. Решарпер может конвертировать туда и обратно по желанию.
usr 8.05.2018 16:13:16

Рико Мариани , гуру .NET Performance, написал статью на эту тему. Это не так просто, как можно подозревать. Основной совет заключается в следующем:

Если ваш шаблон выглядит так:

x = f1(...) + f2(...) + f3(...) + f4(...)

это один конкат, и он быстрым, StringBuilder, вероятно, не поможет.

Если ваш шаблон выглядит так:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

тогда вы, вероятно, хотите StringBuilder.

Еще одна статья, подтверждающая это утверждение, принадлежит Эрику Липперту, в котором он подробно описывает оптимизацию, выполняемую для +конкатенаций в одну строку .

268
26.08.2016 04:37:11
Как насчет String.Format ()?
IronSlug 22.07.2015 08:55:04

Из этой статьи MSDN :

С созданием объекта StringBuilder связаны некоторые накладные расходы, как по времени, так и по памяти. На машине с быстрой памятью стоит использовать StringBuilder, если вы выполняете около пяти операций. Как правило, я бы сказал, что 10 или более строковых операций являются оправданием накладных расходов на любой машине, даже более медленной.

Так что, если вы доверяете MSDN, используйте StringBuilder, если вам нужно выполнить более 10 операций / конкатенаций строк - в противном случае простая конкататация строк с «+» подойдет.

6
22.07.2015 08:51:12

Это действительно зависит от вашей модели использования. Подробный тест между string.Join, string, Concat и string.Format можно найти здесь: String.Format не подходит для интенсивной регистрации

(На самом деле это тот же ответ, который я дал на этот вопрос)

1
29.04.2019 06:00:23

Существует 6 типов конкатенации строк:

  1. Используя +символ плюс ( ).
  2. Используя string.Concat().
  3. Используя string.Join().
  4. Используя string.Format().
  5. Используя string.Append().
  6. Используя StringBuilder.

В эксперименте было доказано, что string.Concat()это лучший способ приблизиться, если слова меньше 1000 (приблизительно) и если слова больше 1000, тогда StringBuilderследует использовать.

Для получения дополнительной информации, проверьте этот сайт .

string.Join () против string.Concat ()

Метод string.Concat здесь эквивалентен вызову метода string.Join с пустым разделителем. Добавление пустой строки - это быстро, но не делать это даже быстрее, поэтому здесь лучше использовать метод string.Concat .

82
26.01.2017 12:51:12
Если читать это было доказано string.Concat () или + это лучший способ. Да, я могу получить это из статьи, но это спасает меня одним кликом. Итак, + и concat компилируются в один и тот же код.
brumScouse 7.08.2015 13:51:18
Я использовал эту основу, чтобы попытаться сделать мой метод более эффективным, где мне нужно было только объединить ровно 3 строки. Я обнаружил, что на +самом деле это было на 3 миллисекунды быстрее string.Concat(), хотя я не изучал количество строк, необходимых перед string.Concat()расправой +.
Gnemlock 9.11.2018 06:13:57

Также важно указать, что вы должны использовать +оператор, если объединяете строковые литералы .

Когда вы объединяете строковые литералы или строковые константы с помощью оператора +, компилятор создает одну строку. Конкатенация во время выполнения не происходит.

Как: объединить несколько строк (Руководство по программированию в C #)

5
14.10.2013 17:15:53

System.String является неизменным. Когда мы изменяем значение строковой переменной, то новому значению выделяется новая память, а предыдущее выделение памяти освобождается. System.StringBuilder был разработан, чтобы иметь концепцию изменяемой строки, где различные операции могут выполняться без выделения отдельного места в памяти для измененной строки.

1
24.04.2014 10:27:10

Добавляя к другим ответам, имейте в виду, что StringBuilder может сказать начальный объем памяти для выделения .

Параметр емкости определяет максимальное количество символов, которое может быть сохранено в памяти, выделенной текущим экземпляром. Его значение присваивается свойству Capacity . Если количество символов, которые будут сохранены в текущем экземпляре, превышает это значение емкости , объект StringBuilder выделяет дополнительную память для их хранения.

Если емкость равна нулю, используется емкость по умолчанию для конкретной реализации.

Повторное добавление в StringBuilder, который не был предварительно выделен, может привести к большому количеству ненужных выделений, как многократное объединение обычных строк.

Если вы знаете, какой длины будет последняя строка, можете легко ее вычислить или можете сделать обоснованное предположение об общем случае (выделение слишком большого количества данных не обязательно является плохой вещью), вам следует предоставить эту информацию конструктору или Емкость свойство. Особенно при запуске тестов производительности для сравнения StringBuilder с другими методами, такими как String.Concat, которые делают то же самое внутри. Любой тест, который вы видите в сети и который не включает предварительное распределение StringBuilder в своих сравнениях, неверен.

Если вы не можете догадаться о размере, вы, вероятно, пишете вспомогательную функцию, которая должна иметь собственный необязательный аргумент для управления предварительным распределением.

5
31.10.2014 17:43:24

Попробуйте это 2 куска кода, и вы найдете решение.

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

Vs

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

Вы обнаружите, что первый код закончится очень быстро, и память будет в хорошем количестве.

Второй код, возможно, память будет в порядке, но это займет больше времени ... намного дольше. Так что, если у вас есть приложение для большого количества пользователей и вам нужна скорость, используйте 1-й. Если у вас есть приложение для краткосрочного однопользовательского приложения, возможно, вы можете использовать оба, или второе будет более «естественным» для разработчиков.

Приветствия.

2
1.01.2016 17:25:37

Ниже может быть еще одно альтернативное решение для объединения нескольких строк.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

интерполяция строк

4
22.09.2017 21:29:50
Это на самом деле удивительно хорошо, как общий метод конкатенации. Это в принципе, String.Formatно более читабельно и с ним легче работать. Разметка его, это немного медленнее , чем +и String.Concatна одной линии сцеплений , но гораздо лучше , чем оба из тех , при повторных вызовах делает StringBuilderменее необходимым.
u8it 22.09.2017 20:24:21

Вот самый быстрый метод, который я развил за десятилетие для моего крупномасштабного приложения НЛП. У меня есть варианты для IEnumerable<T>и других типов ввода, с и без разделителей различных типов ( Char, String), но здесь я показываю простой случай объединения всех строк в массиве в одну строку, без разделителя. Последняя версия здесь разработана и протестирована на C # 7 и .NET 4.7 .

Есть два ключа для повышения производительности; Во-первых, необходимо предварительно рассчитать точный общий требуемый размер. Этот шаг является тривиальным, когда вход представляет собой массив, как показано здесь. Для обработки IEnumerable<T>вместо этого стоит сначала собрать строки во временный массив для вычисления этой общей суммы (массив требуется, чтобы не вызывать ToString()более одного раза на элемент, так как технически, учитывая возможность побочных эффектов, это может изменить ожидаемую семантику операции 'string join').

Далее, с учетом общего размера выделения последней строки, наибольшее повышение производительности достигается путем создания строки результата на месте . Для этого требуется (возможно, противоречивая) техника временной приостановки неизменности нового, Stringкоторый изначально выделен полными нулями. Любой такой спор в стороне, однако ...

... Заметьте , что это единственный в массе конкатенации решение на этой странице полностью избегает дополнительный раунд выделения и копирования со стороны Stringконструктора.

Полный код:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(default(Char), cch)))
    {
        Char* pDst = _p + cch;
        do
            if ((t = rg[--i]).Length > 0)
                fixed (Char* pSrc = t)
                    memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
        while (pDst > _p);
    }
    return s;
}

[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);

Я должен отметить, что этот код имеет небольшие изменения по сравнению с тем, что я использую сам. В оригинале, я называю cpblk IL инструкции от C # для фактического копирования. Для простоты и переносимости в коде я заменил это на P / Invoke memcpy, как вы можете видеть. Для достижения максимальной производительности на x64 ( но, возможно, не на x86 ) вы можете вместо этого использовать метод cpblk .

9
10.11.2017 22:06:05
string.Joinделает все эти вещи уже для вас. Там нет необходимости писать это самостоятельно. Он вычисляет размер последней строки, создает строку этого размера и затем записывает в базовый массив символов. У этого даже есть бонус использования читаемых имен переменных в процессе.
Servy 10.11.2017 22:09:46
@Servy Спасибо за комментарий; действительно String.Joinможет быть эффективным. Как я уже говорил во введении, этот код является просто самой простой иллюстрацией семейства функций, которые я использую для сценариев, которые String.Joinлибо не обрабатываются (например, оптимизируются для Charразделителя), либо не обрабатывались в предыдущих версиях .NET. Я полагаю, что я не должен был выбирать это для простейшего примера, так как это случай, который String.Joinуже хорошо справляется, хотя и с «неэффективностью», вероятно, неизмеримой, обработки пустого разделителя, а именно. String.Empty,
Glenn Slayden 10.11.2017 22:22:41
Конечно, в случае, если у вас нет разделителя, тогда вы должны позвонить Concat, что также делает это правильно. В любом случае вам не нужно писать код самостоятельно.
Servy 10.11.2017 22:25:55
@Servy Я сравнил производительность String.Joinс моим кодом, используя этот тестовый комплект . Для 10 миллионов операций произвольной конкатенации, каждая из которых содержит до 100 строк размером в слово, приведенный выше код всегда на 34% быстрее, чем String.Joinв сборке x64 с .NET 4.7 . Поскольку OP явно запрашивает «самый эффективный» метод, результат предполагает, что мой ответ применим. Если это решит ваши проблемы, я приглашаю вас пересмотреть свое отрицательное мнение.
Glenn Slayden 12.11.2017 03:39:34
Это выглядит довольно аккуратно!
Zimano 14.12.2017 20:22:14

Другое решение:

внутри цикла используйте список вместо строки.

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

это очень очень быстро

1
19.01.2018 12:19:52