C#或Java:用StringBuilder预定string?
我知道我们可以使用StringBuilder
附加string。 有没有一种方法,我们可以预先使用StringBuilder
string(即在string前添加string),所以我们可以保持StringBuilder
提供的性能优势?
使用位置参数设置为0的插入方法将与预先设置相同(即在开始时插入)。
它适用于C#和Java
预先添加一个string通常需要在插入点之后复制一些内容到backing数组中,所以不会像追加到最后一样快。
但是你可以在Java中这样做(在C#中它是一样的,但是这个方法被称为Insert
):
aStringBuilder.insert(0, "newText");
如果你需要很多前置的高性能,你需要编写你自己的StringBuilder
版本(或者使用别人的版本)。 使用标准的StringBuilder
(尽pipe在技术上可以以不同的方式实现)插入需要在插入点之后复制数据。 插入n段文字可能需要O(n ^ 2)次。
一个天真的做法是将补偿添加到支持char[]
缓冲区以及长度。 如果没有足够的空间进行预先安排,则将数据向上移动是必要的。 这可以使性能回落到O(n log n)(我认为)。 更精细的方法是使缓冲区循环。 这样arrays两端的备用空间变得连续。
你可以build立反向的string,然后扭转结果。 您将承担O(n)的成本,而不是O(n ^ 2)最差的成本。
StringBuilder str = new StringBuilder(); str.Insert(0, "text");
编辑:格式化的代码
你可以尝试一个扩展方法:
/// <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声音耐人寻味。 项目名称是一个字的戏剧,使用绳子而不是一个string严重的工作。 获取前置和其他操作的性能损失。 值得一看,如果你将要做很多这个。
绳子是弦乐器的高性能替代品。 在“Ropes:string的替代”中详细描述的数据结构提供了比String和StringBuffer更好的性能,例如prepend,append,delete和insert等常见的string修改。 像string一样,绳索是不可变的,因此非常适合在multithreading编程中使用。
如果我正确理解你, 插入方法看起来像它会做你想要的。 只需在偏移量0处插入string即可。
尝试使用Insert()
StringBuilder MyStringBuilder = new StringBuilder("World!"); MyStringBuilder.Insert(0,"Hello "); // Hello World!
从其他评论来看,没有标准的快捷方式。 使用StringBuilder的.Insert(0, "text")
大约只有使用痛苦的慢string连接(基于> 10000连续)的1-3倍,所以下面是一个类可能潜伏数千倍更快!
我已经包含了一些其他的基本function,例如append()
, subString()
和length()
等等。两个附加和前置的变化约为StringBuilder追加速度的两倍。 像StringBuilder一样,当文本溢出旧的缓冲区大小时,该类中的缓冲区将自动增加。
代码已经testing了很多,但我不能保证它没有错误。
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创build一个扩展:
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的类中,任何时候使用一个StringBuildervariables来实现智能感,Prepend和PrependLine方法都会显示出来。 只要记住,当你使用Prepend时,你将需要按照和Appending相反的顺序进行前置。
这应该工作:
aStringBuilder = "newText" + aStringBuilder;