C# или Java: добавить строки с помощью StringBuilder?


Я знаю, что мы можем добавить строки с помощью StringBuilder. Есть ли способ, которым мы можем добавить строки (т. е. добавить строки перед строкой) с помощью StringBuilder таким образом, мы можем сохранить преимущества производительности, которые StringBuilder предложения?

12 89

12 ответов:

использование метода insert с параметром position, установленным в 0, будет таким же, как и добавление (т. е. вставка в начале).

Это работает как для C# и Java

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

но вы можете сделать это в Java (в C# это то же самое, но метод называется Insert):

aStringBuilder.insert(0, "newText");

Если вам требуется высокая производительность с большим количеством добавлений, вам нужно будет написать свою собственную версию StringBuilder (или использовать чужие). Со стандартом StringBuilder (хотя технически это может быть реализовано по-разному) вставьте требуют копирования данных после точки вставки. Вставка n фрагментов текста может занять O (n^2) времени.

наивным подходом было бы добавить смещение в поддержку char[] буфер, а также длина. Когда не хватает места для начало двигаться данные выше, чем это строго необходимо. Это может привести к снижению производительности до O (N log n) (я думаю). Более утонченный подход состоит в том, чтобы сделать буфер циклическим. Таким образом, свободное пространство на обоих концах массива становится непрерывным.

StringBuilder str = new StringBuilder();
str.Insert(0, "text");

Edit:formated code

вы можете попробовать метод расширения:

/// <summary>
/// kind of a dopey little one-off for StringBuffer, but 
/// an example where you can get crazy with extension methods
/// </summary>
public static void Prepend(this StringBuilder sb, string s)
{
    sb.Insert(0, s);
}

StringBuilder sb = new StringBuilder("World!");
sb.Prepend("Hello "); // Hello World!

Я не использовал его, но Веревки Для Java звучит интригующе. Название проекта-это игра слов, используйте трос вместо строка для серьезной работы. Получает вокруг штрафа за производительность для подготовки и других операций. Стоит посмотреть, если вы собираетесь делать много такого.

веревочка высокая эффективность замены для строк. Этот структура данных, подробно описанная в разделе "Веревки: альтернатива струнам", обеспечивает асимптотически лучше производительность, чем как строка, так и StringBuffer для общие строку изменения, такие как добавить, добавить, удалить и вставить. Как Струны, канаты являются неизменными и, следовательно, хорошо подходит для использования в многопоточных программирование.

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

Если я правильно понял, то вставить метод похоже, он будет делать то, что вы хотите. Просто вставьте строку со смещением 0.

попробуйте использовать вставить()

StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!

судя по другим комментариям, нет стандартного быстрого способа сделать это. С помощью класса StringBuilder это .Insert(0, "text") примерно в 1-3 раза быстрее, чем при использовании мучительно медленной конкатенации строк (на основе >10000 конкатенаций), поэтому ниже приведен класс для добавления потенциально в тысячи раз быстрее!

я включил некоторые другие основные функции, такие как append(),subString() и length() etc. Оба добавления и добавления изменяются примерно в два раза быстрее и в 3 раза медленнее, чем StringBuilder добавляет. Как и StringBuilder, буфер в этом классе будет автоматически увеличиваться, когда текст переполняет старый размер буфера.

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

class Prepender
{
    private char[] c;
    private int growMultiplier;
    public int bufferSize;      // Make public for bug testing
    public int left;            // Make public for bug testing
    public int right;           // Make public for bug testing
    public Prepender(int initialBuffer = 1000, int growMultiplier = 10)
    {
        c = new char[initialBuffer];
        //for (int n = 0; n < initialBuffer; n++) cc[n] = '.';  // For debugging purposes (used fixed width font for testing)
        left = initialBuffer / 2;
        right = initialBuffer / 2;
        bufferSize = initialBuffer;
        this.growMultiplier = growMultiplier;
    }
    public void clear()
    {
        left = bufferSize / 2;
        right = bufferSize / 2;
    }
    public int length()
    {
        return right - left;
    }

    private void increaseBuffer()
    {
        int nudge = -bufferSize / 2;
        bufferSize *= growMultiplier;
        nudge += bufferSize / 2;
        char[] tmp = new char[bufferSize];
        for (int n = left; n < right; n++) tmp[n + nudge] = c[n];
        left += nudge;
        right += nudge;
        c = new char[bufferSize];
        //for (int n = 0; n < buffer; n++) cc[n]='.';   // For debugging purposes (used fixed width font for testing)
        for (int n = left; n < right; n++) c[n] = tmp[n];
    }

    public void append(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (right + s.Length > bufferSize) increaseBuffer();

        // Append user input to buffer
        int len = s.Length;
        for (int n = 0; n < len; n++)
        {
            c[right] = s[n];
            right++;
        }
    }
    public void prepend(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (left - s.Length < 0) increaseBuffer();               

        // Prepend user input to buffer
        int len = s.Length - 1;
        for (int n = len; n > -1; n--)
        {
            left--;
            c[left] = s[n];
        }
    }
    public void truncate(int start, int finish)
    {
        if (start < 0) throw new Exception("Truncation error: Start < 0");
        if (left + finish > right) throw new Exception("Truncation error: Finish > string length");
        if (finish < start) throw new Exception("Truncation error: Finish < start");

        //MessageBox.Show(left + " " + right);

        right = left + finish;
        left = left + start;
    }
    public string subString(int start, int finish)
    {
        if (start < 0) throw new Exception("Substring error: Start < 0");
        if (left + finish > right) throw new Exception("Substring error: Finish > string length");
        if (finish < start) throw new Exception("Substring error: Finish < start");
        return toString(start,finish);
    }

    public override string ToString()
    {
        return new string(c, left, right - left);
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
    private string toString(int start, int finish)
    {
        return new string(c, left+start, finish-start );
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
}

вы можете создать расширение для StringBuilder самостоятельно с помощью простого класса:

namespace Application.Code.Helpers
{
    public static class StringBuilderExtensions
    {
        #region Methods

        public static void Prepend(this StringBuilder sb, string value)
        {
            sb.Insert(0, value);
        }

        public static void PrependLine(this StringBuilder sb, string value)
        {
            sb.Insert(0, value + Environment.NewLine);
        }

        #endregion
    }
}

затем просто добавить:

using Application.Code.Helpers;

в верхней части любого класса, в котором вы хотите использовать StringBuilder, и в любое время, когда вы используете intelli-sense с переменной StringBuilder, будут отображаться методы Prepend и PrependLine. Просто помните, что когда вы используете Prepend, вам нужно будет добавить в обратном порядке, чем если бы вы добавляли.

Это должно работать:

aStringBuilder = "newText" + aStringBuilder;