IEnumerable to string

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 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()); 

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 recostack 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 comstackció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 seq = Enumerable.Repeat('a', 300); static string ToArrayString(IEnumerable charSequence) { return new String(charSequence.ToArray()); } static string Concat(IEnumerable charSequence) { return String.Concat(charSequence); } static string StringBuilderChars(IEnumerable charSequence) { var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c); } return sb.ToString(); } static string StringBuilderStrings(IEnumerable 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 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.

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

 string.Concat(myEnumerable); 

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 characters) { return String.Concat(characters); } public static string AsStringNew(this IEnumerable characters) { return new String(characters.ToArray()); } public static string AsStringSb(this IEnumerable 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)RandomString(STRLEN)).Reverse()

Resultados

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

Entrada

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

Resultados

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

Entrada

  • ((IEnumerable)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.

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 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.