Pregunta

¿Cuál es la forma más eficaz de concatenar cadenas?

¿Fue útil?

Solución

El StringBuilder.Append() El método es mucho mejor que usar el operador +.Pero descubrí que, al ejecutar 1000 concatenaciones o menos, String.Join() es incluso más eficiente que StringBuilder.

StringBuilder sb = new StringBuilder();
sb.Append(someString);

El único problema con String.Join es que hay que concatenar las cadenas con un delimitador común.(Editar :) como señaló @ryanversaw, puede hacer que la cadena delimitadora esté vacía.

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });

Otros consejos

marian rico, el gurú del rendimiento de .NET, había un artículo sobre este mismo tema.No es tan simple como podría sospecharse.El consejo básico es este:

Si tu patrón se parece a:

x = f1(...) + f2(...) + f3(...) + f4(...)

ese es un concat y es rápido, StringBuilder probablemente no ayude.

Si tu patrón se parece a:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

entonces probablemente quieras StringBuilder.

Otro artículo más para respaldar esta afirmación. proviene de Eric Lippert donde describe las optimizaciones realizadas en una línea + concatenaciones de manera detallada.

Hay 6 tipos de concatenaciones de cadenas:

  1. Usando el signo más (+) símbolo.
  2. Usando string.Concat().
  3. Usando string.Join().
  4. Usando string.Format().
  5. Usando string.Append().
  6. Usando StringBuilder.

En un experimento se ha demostrado que string.Concat() es la mejor manera de abordar si las palabras son menos de 1000 (aproximadamente) y si las palabras son más de 1000 entonces StringBuilder debería ser usado.

Para más información, consulte esto sitio.

cadena.Join() vs cadena.Concat()

El método string.Concat aquí es equivalente a la invocación del método string.Join con un separador vacío.Agregar una cadena vacía es rápido, pero no hacerlo es aún más rápido, por lo que cadena.Concat El método sería superior aquí.

De Chinh Do: StringBuilder no siempre es más rápido:

Reglas de juego

  • Al concatenar tres valores de cadena dinámicos o menos, utilice la concatenación de cadenas tradicional.

  • Al concatenar más de tres valores de cadena dinámica, utilice StringBuilder.

  • Al crear una cadena grande a partir de varios literales de cadena, utilice el literal de cadena @ o el operador + en línea.

Mayoría de las veces StringBuilder es tu mejor opción, pero hay casos, como se muestra en esa publicación, en los que al menos deberías pensar en cada situación.

Si está operando en un bucle, StringBuilder es probablemente el camino a seguir;le ahorra la sobrecarga de crear nuevas cadenas con regularidad.Sin embargo, en un código que solo se ejecutará una vez, String.Concat probablemente esté bien.

Sin embargo, Rico Mariani (gurú de la optimización .NET) hizo una prueba en el que afirma al final que, en la mayoría de los casos, recomienda String.Format.

Este es el método más rápido que he desarrollado durante una década para mi aplicación de PNL a gran escala.tengo variaciones para IEnumerable<T> y otros tipos de entrada, con y sin separadores de diferentes tipos (Char, String), pero aquí muestro el caso simple de concatenando todas las cadenas en una matriz en una sola cadena, sin separador.La última versión aquí está desarrollada y probada en unidades C#7 y NET 4.7.

Hay dos claves para un mayor rendimiento;la primera es calcular previamente el tamaño total exacto requerido.Este paso es trivial cuando la entrada es una matriz como se muestra aquí.Para la manipulación IEnumerable<T> en su lugar, primero vale la pena reunir las cadenas en una matriz temporal para calcular ese total (la matriz es necesaria para evitar llamar ToString() más de una vez por elemento ya que técnicamente, dada la posibilidad de efectos secundarios, hacerlo podría cambiar la semántica esperada de una operación de 'unión de cadenas').

A continuación, dado el tamaño total de asignación de la cadena final, el mayor impulso en el rendimiento se obtiene mediante construyendo la cadena de resultados en el lugar.Hacer esto requiere la técnica (quizás controvertida) de suspender temporalmente la inmutabilidad de un nuevo String que inicialmente se asigna lleno de ceros.Sin embargo, dejando de lado cualquier controversia de este tipo...

... tenga en cuenta que esta es la única solución de concatenación masiva en esta página que evita por completo una ronda extra de asignación y copia por el String constructor.

Código completo:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(default(Char), cch)))
    {
        Char* pDst = _p + cch;
        do
            if ((t = rg[--i]).Length > 0)
                fixed (Char* pSrc = t)
                    memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
        while (pDst > _p);
    }
    return s;
}

[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);

Debo mencionar que este código tiene una ligera modificación con respecto al que uso yo mismo.En el original, yo llama a cpblk instrucción IL de C# para hacer la copia real.Para simplificar y portabilidad en el código aquí, lo reemplacé con P/Invoke memcpy en cambio, como puedes ver.Para obtener el máximo rendimiento en x64 (pero tal vez no x86) es posible que desee utilizar el cpblk método en su lugar.

De esto artículo de MSDN:

Hay algunas sobrecargas asociadas con la creación de un objeto StringBuilder, tanto en el tiempo como en la memoria.En una máquina con memoria rápida, un StringBuilder vale la pena si está haciendo aproximadamente cinco operaciones.Como regla general, diría que 10 o más operaciones de cadena son una justificación para la sobrecarga en cualquier máquina, incluso más lenta.

Entonces, si confía en MSDN, elija StringBuilder si tiene que realizar más de 10 operaciones/concatenaciones de cadenas; de lo contrario, una simple concatenación de cadenas con '+' está bien.

Además de las otras respuestas, tenga en cuenta que A StringBuilder se le puede indicar una cantidad inicial de memoria para asignar.

El capacidad El parámetro define el número máximo de caracteres que se pueden almacenar en la memoria asignada por la instancia actual.Su valor se asigna a la Capacidad propiedad.Si el número de caracteres que se almacenarán en la instancia actual excede este capacidad valor, el objeto StringBuilder asigna memoria adicional para almacenarlos.

Si capacidad es cero, se utiliza la capacidad predeterminada específica de la implementación.

Agregar repetidamente a un StringBuilder que no ha sido preasignado puede resultar en muchas asignaciones innecesarias, al igual que concatenar repetidamente cadenas normales.

Si sabe cuánto durará la cadena final, puede calcularla trivialmente o puede hacer una suposición fundamentada sobre el caso común (asignar demasiado no es necesariamente algo malo), debe proporcionar esta información al constructor o al Capacidad propiedad. Especialmente al ejecutar pruebas de rendimiento para comparar StringBuilder con otros métodos como String.Concat, que hacen lo mismo internamente.Cualquier prueba que vea en línea que no incluya la preasignación de StringBuilder en sus comparaciones es incorrecta.

Si no puede adivinar el tamaño, probablemente esté escribiendo una función de utilidad que debería tener su propio argumento opcional para controlar la preasignación.

También es importante señalar que debes utilizar el + operador si está concatenando literales de cadena.

Cuando concatenas literales de cadena o constantes de cadena usando el operador +, el compilador crea una sola cadena.No se produce ninguna concatenación en tiempo de ejecución.

Cómo:Concatenar varias cadenas (Guía de programación de C#)

La siguiente puede ser una solución alternativa más para concatenar varias cadenas.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

interpolación de cadenas

Lo más eficiente es usar StringBuilder, así:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy:String.Concat está bien si tienes un par de cosas pequeñas.Pero si estás concatenando megabytes de datos, es probable que tu programa fracase.

Pruebe estos 2 fragmentos de código y encontrará la solución.

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

contra

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

Descubrirá que el primer código finalizará muy rápido y la memoria estará en una buena cantidad.

El segundo código tal vez la memoria esté bien, pero llevará más tiempo...mucho mas largo.Entonces, si tienes una aplicación para muchos usuarios y necesitas velocidad, usa el 1er.Si tiene una aplicación para un usuario a corto plazo, tal vez pueda usar ambas o la segunda será más "natural" para los desarrolladores.

Salud.

System.String es inmutable.Cuando modificamos el valor de una variable de cadena, se asigna una nueva memoria al nuevo valor y se libera la asignación de memoria anterior.System.StringBuilder fue diseñado para tener el concepto de una cadena mutable donde se pueden realizar una variedad de operaciones sin asignar una ubicación de memoria separada para la cadena modificada.

Otra solución:

dentro del bucle, use Lista en lugar de cadena.

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

es muy muy rápido.

Realmente depende de su patrón de uso.Puede encontrar un punto de referencia detallado entre string.Join, string,Concat y string.Format aquí: String.Format no es adecuado para el registro intensivo

(Esta es en realidad la misma respuesta que le di a este pregunta)

Para solo dos cadenas, definitivamente no querrás utilizar StringBuilder.Existe un umbral por encima del cual la sobrecarga de StringBuilder es menor que la sobrecarga de asignar varias cadenas.

Entonces, para más de 2-3 cadenas, use El código de DannyPitufo.De lo contrario, simplemente use el operador +.

Dependería del código.StringBuilder es más eficiente en general, pero si solo concatenas unas pocas cadenas y lo haces todo en una línea, las optimizaciones de código probablemente se encargarán de ello por ti.También es importante pensar en cómo se ve el código:para conjuntos más grandes, StringBuilder hará que sea más fácil de leer, para los más pequeños, StringBuilder simplemente agregará desorden innecesario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top