c# - example - stringbuilder vs string
C#o Java: ¿Prefijo cadenas con StringBuilder? (12)
A juzgar por los otros comentarios, no hay una manera estándar rápida de hacerlo. El uso de .Insert(0, "text")
StringBuilder es aproximadamente de solo 1 a 3 veces más rápido que con una concatenación de cadenas muy lenta (basada en> 10000 concats), por lo que a continuación hay una clase para anteponer potencialmente miles de veces más rápido.
He incluido algunas otras funciones básicas, como append()
, subString()
y length()
etc. Tanto los añadidos como los anteriores varían de aproximadamente el doble de rápido a 3 veces más lento que los que se añaden a StringBuilder. Al igual que StringBuilder, el búfer en esta clase aumentará automáticamente cuando el texto se desborde del antiguo tamaño del búfer.
El código ha sido probado bastante, pero no puedo garantizar que esté libre de errores.
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)
}
}
Sé que podemos agregar cadenas usando StringBuilder
. ¿Hay alguna manera de preinstalar cadenas (es decir, agregar cadenas delante de una cadena) usando StringBuilder
para que podamos mantener los beneficios de rendimiento que ofrece StringBuilder
?
Anteponer una Cadena generalmente requerirá copiar todo después del punto de inserción en la matriz de respaldo, por lo que no será tan rápido como agregarlo al final.
Pero puedes hacerlo así en Java (en C # es lo mismo, pero el método se llama Insert
):
aStringBuilder.insert(0, "newText");
Esto debería funcionar:
aStringBuilder = "newText" + aStringBuilder;
Intenta usar C#
StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!
No lo he usado, pero Ropes For Java Sounds es intrigante. El nombre del proyecto es un juego de palabras, use una cuerda en lugar de una cadena para un trabajo serio. Obtiene la penalización de rendimiento para las operaciones de antependencia y otras operaciones. Vale la pena mirar, si vas a hacer mucho de esto.
Una cuerda es un reemplazo de alto rendimiento para cuerdas. La estructura de datos, descrita en detalle en "Cuerdas: una alternativa a las cadenas", proporciona un rendimiento asintóticamente mejor que String y StringBuffer para las modificaciones de cadenas comunes como anteponer, anexar, eliminar e insertar. Al igual que las cuerdas, las cuerdas son inmutables y, por lo tanto, son adecuadas para usar en la programación de múltiples hilos.
Puede crear una extensión para StringBuilder usted mismo con una clase simple:
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
}
}
Entonces, solo agrega:
using Application.Code.Helpers;
En la parte superior de cualquier clase en la que desee utilizar StringBuilder y en cualquier momento que use intelli-sense con una variable StringBuilder, aparecerán los métodos Prefijo y Prependline. Solo recuerde que cuando usa Prefijo, deberá Preceder en orden inverso al que tenía al Anexar.
Puedes construir la cuerda en reversa y luego invertir el resultado. Usted incurre en un costo de O (n) en lugar de un costo de O (n ^ 2) en el peor de los casos.
Puedes probar un método de extensió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!
Si necesita un alto rendimiento con muchos preparativos, tendrá que escribir su propia versión de StringBuilder
(o usar la de otra persona). Con StringBuilder
estándar (aunque técnicamente podría implementarse de manera diferente), insertar requiere copiar datos después del punto de inserción. Insertar n trozo de texto puede tomar O (n ^ 2) tiempo.
Un enfoque ingenuo sería agregar una compensación en el buffer de respaldo char[]
así como la longitud. Cuando no hay espacio suficiente para un antecedente, mueva los datos hacia arriba más de lo estrictamente necesario. Esto puede devolver el rendimiento a O (n log n) (creo). Un enfoque más refinado es hacer que el buffer sea cíclico. De esa forma, el espacio libre en ambos extremos de la matriz se vuelve contiguo.
Si te entiendo correctamente, el método de inserción parece que hará lo que quieras. Solo inserta la cuerda en el desplazamiento 0.
StringBuilder str = new StringBuilder();
str.Insert(0, "text");
Editar: código formateado