c# .net

c# - IEnumerable<char> to string



.net (6)

Esta pregunta ya tiene una respuesta aquí:

Nunca me he encontrado con esto antes, pero ahora y estoy sorprendido de que no puedo encontrar una manera realmente fácil de convertir un IEnumerable<char> en una string .

La mejor forma en que puedo pensar es string str = new string(myEnumerable.ToArray()); , pero, para mí, parece que esto crearía un nuevo char[] , y luego crearía una nueva string partir de eso, lo que parece costoso.

Pensé que esto sería una funcionalidad común integrada en .NET framework en alguna parte. ¿Hay una manera más simple de hacer esto?

Para aquellos interesados, la razón por la que me gustaría usar esto es usar LINQ para filtrar cadenas:

string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());


A partir de .NET 4, muchos métodos de cadena toman IEnumerable como argumentos.

string.Concat(myEnumerable);


Aquí hay una versión más sucinta de la respuesta de StringBuilder:

return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();

Calculé esto usando las mismas pruebas que usó Jeff Mercado y esto fue 1 segundo más lento en 1,000,000 iteraciones en la misma secuencia de 300 caracteres (versión de lanzamiento de 32 bits) que el más explícito:

static string StringBuilderChars(IEnumerable<char> charSequence) { var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c); } return sb.ToString(); }

Entonces, si eres fanático de los acumuladores, aquí tienes.


Mis datos son contrarios a los resultados que Jodrell publicó. Primero eche un vistazo a los métodos de extensión que uso:

public static string AsStringConcat(this IEnumerable<char> characters) { return String.Concat(characters); } public static string AsStringNew(this IEnumerable<char> characters) { return new String(characters.ToArray()); } public static string AsStringSb(this IEnumerable<char> characters) { StringBuilder sb = new StringBuilder(); foreach (char c in characters) { sb.Append(c); } return sb.ToString(); }

Mis resultados

Con

  • STRLEN = 31
  • ITERACIONES = 1000000

Entrada

  • ((IEnumerable<char>)RandomString(STRLEN)).Reverse()

Resultados

  • Concat: 1x
  • Nuevo: 3x
  • StringBuilder: 3x

Entrada

  • ((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)

Resultados

  • Concat: 1x
  • Nuevo: 7x
  • StringBuilder: 7x

Entrada

  • ((IEnumerable<char>)RandomString(STRLEN)) (esto es solo un upcast)

Resultados

  • Concat: 0 ms
  • Nuevo: 2000 ms
  • StringBuilder: 2000 ms
  • Downcast: 0 ms

Ejecuté esto en un Intel i5 760 que apunta .NET Framework 3.5.


Otra posibilidad es usar

string.Join("", myEnumerable);

No medí el rendimiento.


Puede usar String.Concat() .

var allowedString = String.Concat( inputString.Where(c => allowedChars.Contains(c)) );

Advertencia : este enfoque tendrá algunas implicaciones de rendimiento. String.Concat no recopila colecciones de caracteres especiales, por lo que funciona como si cada carácter se convirtiera en una cadena y luego se concatenara como se menciona en la documentación ( y realmente lo hace ). Claro que esto te da una forma integrada para llevar a cabo esta tarea, pero podría hacerse mejor.

No creo que haya implementaciones dentro del marco que tengan char especial, por lo que tendrás que implementarlo. Un bucle simple que anexa caracteres a un generador de cadenas es lo suficientemente simple como para crearlo.

Aquí hay algunos puntos de referencia que tomé en una máquina de desarrollo y se ve bien.

1000000 iteraciones en una secuencia de 300 caracteres en una compilación de lanzamiento de 32 bits:

ToArrayString: 00:00:03.1695463 Concat: 00:00:07.2518054 StringBuilderChars: 00:00:03.1335455 StringBuilderStrings: 00:00:06.4618266

static readonly IEnumerable<char> seq = Enumerable.Repeat(''a'', 300); static string ToArrayString(IEnumerable<char> charSequence) { return new String(charSequence.ToArray()); } static string Concat(IEnumerable<char> charSequence) { return String.Concat(charSequence); } static string StringBuilderChars(IEnumerable<char> charSequence) { var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c); } return sb.ToString(); } static string StringBuilderStrings(IEnumerable<char> charSequence) { var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c.ToString()); } return sb.ToString(); }


Editado para el lanzamiento de .Net Core 2.1

Repitiendo la prueba para el lanzamiento de .Net Core 2.1, obtengo resultados como este

1000000 iteraciones de "Concat" tomaron 842ms.

1000000 iteraciones de "nueva Cadena" tomaron 1009ms.

1000000 iteraciones de "sb" tomaron 902ms.

En resumen, si está utilizando .Net Core 2.1 o posterior, Concat es el rey.

Ver la publicación del blog de MS para más detalles.

He hecho de esto el tema de otra pregunta, pero cada vez más, eso se está convirtiendo en una respuesta directa a esta pregunta.

He hecho algunas pruebas de rendimiento de 3 métodos simples para convertir un IEnumerable<char> en una string , esos métodos son

nueva cadena

return new string(charSequence.ToArray());

Concat

return string.Concat(charSequence)

StringBuilder

var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c); } return sb.ToString();

En mi prueba, que se detalla en la pregunta vinculada , para 1000000 iteraciones de "Some reasonably small test data" obtengo resultados como este,

1000000 iteraciones de "Concat" tomaron 1597ms.

1000000 iteraciones de "nueva cadena" tomaron 869ms.

1000000 iteraciones de "StringBuilder" tomaron 748ms.

Esto me sugiere que no hay una buena razón para usar string.Concat para esta tarea. Si desea simplicidad, use el nuevo enfoque de cadenas y, si lo desea, utilice StringBuilder .

Me gustaría advertir mi afirmación, en la práctica todos estos métodos funcionan bien, y todo esto podría ser más de optimización.