StringBuilder
を使用して文字列を追加できることを知っています。 StringBuilder
を使用して文字列を先頭に追加する(つまり、文字列の前に文字列を追加する)方法があるので、StringBuilder
が提供するパフォーマンス上の利点を維持できますか。
通常、文字列の先頭に追加するには、挿入ポイントの後のすべてをバッキング配列の一部にコピーする必要があるため、末尾に追加するほど迅速ではありません。
ただし、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のStringBuilderクラスを使用して先頭に追加する場合にできることは次のとおりです。
StringBuilder str = new StringBuilder();
str.Insert(0, "text");
私は使っていませんが、 Ropes For Java 興味をそそる音です。プロジェクト名は言葉の遊びです。深刻な作業にはStringではなくRopeを使用します。プリペンディングおよびその他の操作のパフォーマンスペナルティを回避します。あなたがこれの多くをしているつもりなら、一見の価値があります。
ロープは、ストリングの高性能な代替品です。 「ロープ:文字列の代替」で詳細に説明されているデータ構造は、prepend、append、delete、insertなどの一般的な文字列の変更について、StringおよびStringBufferの両方よりも漸近的に優れたパフォーマンスを提供します。ストリングと同様に、ロープは不変であるため、マルチスレッドプログラミングでの使用に適しています。
文字列を逆に構築してから、結果を逆にすることができます。 O(n ^ 2)最悪の場合のコストの代わりにO(n)コストが発生します。
私があなたを正しく理解していれば、 insert method はあなたが望むことをするように見えます。オフセット0に文字列を挿入するだけです。
他のコメントから判断すると、これを行うための標準的な迅速な方法はありません。 StringBuilderの.Insert(0, "text")
の使用は、非常に遅い文字列連結(10000を超える連結に基づく)を使用する場合の約1〜3倍の速さであるため、以下は何千倍も高速に追加するクラスです。
append()
、subString()
、およびlength()
などの基本的な機能を追加しました。追加と追加の両方が、StringBuilderの約2倍から3倍遅いまで変化します。追加します。 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)
}
}
Insert() を使用してみてください
StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!
単純なクラスを使用して、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を使用するクラスの先頭、およびStringBuilder変数でintelli-senseを使用するときは常に、PrependメソッドとPrependLineメソッドが表示されます。 Prependを使用する場合は、Appendingの場合と逆の順序でPrependする必要があることに注意してください。
これは動作するはずです:
aStringBuilder = "newText" + aStringBuilder;