Вопрос

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

это один конкат, и он быстрый, 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() против string.Concat()

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

От Чин До — StringBuilder не всегда быстрее:

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

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

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

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

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

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

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

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

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

Далее, учитывая общий размер выделения конечной строки, наибольший прирост производительности достигается за счет построение результирующей строки на месте.Для этого потребуется метод (возможно, спорный) временного приостановления неизменяемости нового 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 ИЛ-инструкция от С# чтобы выполнить фактическое копирование.Для простоты и переносимости кода я заменил его на P/Invoke. memcpy вместо этого, как вы можете видеть.Для максимальной производительности на x64 (но, возможно, не x86) вы можете использовать cpblk вместо этого метод.

Из этого Статья MSDN:

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

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

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

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

Попробуйте эти 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();
    }

Против

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

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

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

Ваше здоровье.

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top