C# или Java: добавить строки с помощью StringBuilder?
Я знаю, что мы можем добавить строки с помощью StringBuilder
. Есть ли способ, которым мы можем добавить строки (т. е. добавить строки перед строкой) с помощью StringBuilder
таким образом, мы можем сохранить преимущества производительности, которые StringBuilder
предложения?
12 ответов:
добавление строки обычно требует копирования всего после точки вставки обратно в резервный массив, поэтому это будет не так быстро, как добавление до конца.
но вы можете сделать это в Java (в C# это то же самое, но метод называется
Insert
):aStringBuilder.insert(0, "newText");
Если вам требуется высокая производительность с большим количеством добавлений, вам нужно будет написать свою собственную версию
StringBuilder
(или использовать чужие). Со стандартомStringBuilder
(хотя технически это может быть реализовано по-разному) вставьте требуют копирования данных после точки вставки. Вставка n фрагментов текста может занять O (n^2) времени.наивным подходом было бы добавить смещение в поддержку
char[]
буфер, а также длина. Когда не хватает места для начало двигаться данные выше, чем это строго необходимо. Это может привести к снижению производительности до O (N log n) (я думаю). Более утонченный подход состоит в том, чтобы сделать буфер циклическим. Таким образом, свободное пространство на обоих концах массива становится непрерывным.
вы можете попробовать метод расширения:
/// <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, вам нужно будет добавить в обратном порядке, чем если бы вы добавляли.