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

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

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

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

Единственная проблема с String.Join заключается в том, что вам нужно String.Join строки с общим разделителем. (Edit :), как указывал @ryanversaw, вы можете сделать разделитель string.Empty.

 string key = String.Join("_", new String[] { "Customers_Contacts", customerID, database, SessionID }); 

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

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

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

это один concat, и это zippy, StringBuilder, вероятно, не поможет.

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

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

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

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

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

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

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

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

string.Join () vs string.Concat ()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Полный код:

 ///  /// Concatenate the strings in 'rg', none of which may be null, into a single String. ///  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 .

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

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

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

Неоднократное добавление к StringBuilder, который не был предварительно выделен, может привести к множеству ненужных распределений, как многократно конкатенации регулярных строк.

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

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

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

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

Практическое руководство. Объединение нескольких строк (руководство по программированию на C #)

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

 String str1 = "sometext"; string str2 = "some other text"; string afterConcate = $"{str1}{str2}"; 

строчная интерполяция

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

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

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

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

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

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

Попробуйте эти 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-й код закончится очень быстро, и память будет в хорошем количестве.

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

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

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

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

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

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

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

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

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

  • Форматировать строки в методе Console.WriteLine
  • Получить индекс n-го вхождения строки?
  • Что означает {0}, когда он найден в строке в C #?
  • Что такое возврат каретки, перевод строки и фид?
  • Является ли строка Java действительно неизменной?
  • Подстрочный индекс и надстрочный указатель строки в Android
  • Разделение строки Java удалено пустым значением
  • Разделить строку на слова несколькими разделителями
  • Строка C ++ для enums
  • Заполнение строк в C
  • Как запустить TestNG из командной строки
  • Давайте будем гением компьютера.