2008-09-28 19 views
87

que tienen una matriz de enteros:Cómo unir int [] a una cadena separada por caracteres en .NET?

int[] number = new int[] { 2,3,6,7 }; 

¿Cuál es la forma más fácil de convertir éstos en una sola cadena, donde los números están separados por un carácter (como: "2,3,6,7")?

Estoy en C# y .NET 3.5.

+2

SO rocks! ¡Recibí estas 3 respuestas excelentes en 10 minutos en un domingo! – Riri

+3

A partir de '.NET 4.0' hay métodos que toman una matriz de objetos y un IEnumerable para que pueda hacer' string.join (",", number) '. Sé que la pregunta especifica .NET 3.5, así que no hice de esto una respuesta, pero aparece en búsquedas que no especifican una versión y saber que es posible en 4.0 podría ayudar a alguien. –

Respuesta

144
var ints = new int[] {1, 2, 3, 4, 5}; 
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray()); 
Console.WriteLine(result); // prints "1,2,3,4,5" 

EDITAR:

Veo varias soluciones anuncian el uso de StringBuilder. Alguien se queja de que el método Join debería tomar un argumento IEnumerable.

Voy a decepcionarte :) String.Join requiere una matriz por una sola razón: el rendimiento. El método Join necesita conocer el tamaño de los datos para preasignar de manera efectiva la cantidad necesaria de memoria.

Aquí está una parte de la implementación interna del método string.join:

// length computed from length of items in input array and length of separator 
string str = FastAllocateString(length); 
fixed (char* chRef = &str.m_firstChar) // note than we use direct memory access here 
{ 
    UnSafeCharBuffer buffer = new UnSafeCharBuffer(chRef, length); 
    buffer.AppendString(value[startIndex]); 
    for (int j = startIndex + 1; j <= num2; j++) 
    { 
     buffer.AppendString(separator); 
     buffer.AppendString(value[j]); 
    } 
} 

soy demasiado perezoso para comparar el rendimiento de los métodos sugeridos. Pero algo me dice que se incorporen a ganar :)

+0

Esta es probablemente la mejor opción para usar los métodos de extensión core .NET, pero realmente deseaba que string.Join() aceptara un IEnumerable para evitar la conversión de ToArray(). – spoulson

+0

Nada impide que alguien sobrecargue la cuerda. Únete para tomar un IEnumerable, también. ;) –

+1

Probablemente también sea la solución más fácil, y no solo la más rápida. –

8
String.Join(";", number.Select(item => item.ToString()).ToArray()); 

Tenemos que convertir cada uno de los elementos a una String antes de poder unirse a ellos, así que tiene sentido utilizar Select y una expresión lambda. Esto es equivalente a map en algunos otros idiomas. Luego tenemos que convertir la colección resultante de cadena a una matriz, porque String.Join solo acepta una matriz de cadenas.

El ToArray() es un poco feo, creo. String.Join realmente debería aceptar IEnumerable<String>, no hay ninguna razón para restringirlo solo a las matrices. Probablemente sea porque Join es anterior a los genéricos, cuando las matrices eran el único tipo de colección tipada disponible.

5

Si su matriz de enteros puede ser grande, obtendrá un mejor rendimiento utilizando un StringBuilder. Ej .:

StringBuilder builder = new StringBuilder(); 
char separator = ','; 
foreach(int value in integerArray) 
{ 
    if (builder.Length > 0) builder.Append(separator); 
    builder.Append(value); 
} 
string result = builder.ToString(); 

Editar: Cuando publiqué este estaba bajo la impresión equivocada de que "StringBuilder.Append (int value)" administradas internamente para anexar la representación de cadena del valor entero sin crear un objeto de cadena. Esto es incorrecto: inspeccionar el método con Reflector muestra que simplemente agrega value.ToString().

Por lo tanto, la única diferencia de rendimiento potencial es que esta técnica evita la creación de una matriz y libera las cadenas para la recolección de basura antes. En la práctica, esto no supondrá ninguna diferencia medible, por lo que he subido this better solution.

+0

¿Lo has medido para que sea más rápido? String.Join también usa un StringBuilder. – JacquesB

+0

Sí, pero primero debe convertir todo el conjunto en una matriz, que está lejos de ser ideal. En particular, significa que necesita tener todas las cadenas convertidas en memoria al mismo tiempo, * antes * de que empiece a construir la cadena resultante. –

+0

OTOH String.Join precalcula el tamaño del búfer StringBuilder para evitar el cambio de tamaño. Por lo tanto, podría ser más rápido incluso si requiere más memoria. – JacquesB

10

Una mezcla de los dos enfoques sería escribir un método de extensión en IEnumerable < T> que utiliza un StringBuilder. Aquí hay un ejemplo, con diferentes sobrecargas dependiendo de si desea especificar la transformación o simplemente confiar en ToString simple. He nombrado el método "JoinStrings" en lugar de "Join" para evitar confusiones con el otro tipo de Join.Tal vez alguien puede subir con un nombre mejor :)

using System; 
using System.Collections.Generic; 
using System.Text; 

public static class Extensions 
{ 
    public static string JoinStrings<T>(this IEnumerable<T> source, 
             Func<T, string> projection, string separator) 
    { 
     StringBuilder builder = new StringBuilder(); 
     bool first = true; 
     foreach (T element in source) 
     { 
      if (first) 
      { 
       first = false; 
      } 
      else 
      { 
       builder.Append(separator); 
      } 
      builder.Append(projection(element)); 
     } 
     return builder.ToString(); 
    } 

    public static string JoinStrings<T>(this IEnumerable<T> source, string separator) 
    { 
     return JoinStrings(source, t => t.ToString(), separator); 
    } 
} 

class Test 
{ 

    public static void Main() 
    { 
     int[] x = {1, 2, 3, 4, 5, 10, 11}; 

     Console.WriteLine(x.JoinStrings(";")); 
     Console.WriteLine(x.JoinStrings(i => i.ToString("X"), ",")); 
    } 
} 
+0

¡Buena solución! Sin embargo, no necesita el parámetro de proyección, simplemente puede escribir x. Seleccionar (i => i.ToString ("X")). JoinStrings (";") que es más idiomático. – JacquesB

+0

Sí, pensé en eso luego. Ocasionalmente, es bueno poder especificarlo todo de una vez, pero definitivamente es más elegante dividir las operaciones :) –

2

Estoy de acuerdo con la expresión lambda para mejorar la legibilidad y facilidad de mantenimiento, pero no siempre será la mejor opción. La desventaja de utilizar los enfoques IEnumerable/ToArray y StringBuilder es que tienen que hacer crecer dinámicamente una lista, ya sea de elementos o caracteres, ya que no saben cuánto espacio se necesitará para la cadena final.

Si el raro caso donde la velocidad es más importante que la concisión, lo siguiente es más eficiente.

int[] number = new int[] { 1, 2, 3, 4, 5 }; 
string[] strings = new string[number.Length]; 
for (int i = 0; i < number.Length; i++) 
    strings[i] = number[i].ToString(); 
string result = string.Join(",", strings); 
32

Aunque el PO especifica .NET 3.5, la gente que quiere hacer esto en .NET 2.0 con C# 2 puede haz esto:

string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString)); 

Encuentro que hay un número de otros casos en los que el uso de las funciones Convert.xxx es una alternativa más ordenada que una lambda, aunque en C# 3, la lambda podría ayudar a la inferencia de tipos.

Una versión bastante compacto C# 3, que trabaja con .NET 2.0 es la siguiente:

string.Join(",", Array.ConvertAll(ints, item => item.ToString())) 
+2

Y esto funciona en la ventana de Inspección mientras depuración –

2
ints.Aggregate("", (str, n) => str +","+ n).Substring(1); 

También pensé que había una manera más simple. No sé sobre el rendimiento, ¿alguien tiene alguna idea (teórica)?

+0

Esta solución le daría ", 1,2,3,4,5". – user347805

+0

Gracias, he agregado 'Substring (1)' para arreglar eso (era de memoria). – void

5

La pregunta es por "la manera más fácil de convertir estos en una sola cadena donde el número está separado por un carácter".

La forma más sencilla es:

int[] numbers = new int[] { 2,3,6,7 }; 
string number_string = string.Join(",", numbers); 
// do whatever you want with your exciting new number string 

EDIT: Esto sólo funciona en .NET 4.0 y versiones superiores, que se perdió el requisito .NET 3.5 la primera vez que leí la pregunta.

+0

Esto no es válido como cadena. El método de unión solo toma una matriz de cadenas. Eche un vistazo aquí http://msdn.microsoft.com/en-us/library/tk0xe5h0.aspx – ppolyzos

+1

Es un método sobrecargado: http://msdn.microsoft.com/en-us/library/dd988350 Acabo de Copié el código que escribí en una nueva aplicación de consola, agregué una Console.WriteLine y esta es la salida: 2,3,6,7 – WebMasterP

+1

Creo que esto está disponible solo en .net 4 –

1

En .NET 4.0, cadena de combinación tiene una sobrecarga de params object[], por lo que es tan simple como:

int[] ids = new int[] { 1, 2, 3 }; 
string.Join(",", ids); 

ejemplo

int[] ids = new int[] { 1, 2, 3 }; 
System.Data.Common.DbCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM some_table WHERE id_column IN (@bla)"); 
cmd.CommandText = cmd.CommandText.Replace("@bla", string.Join(",", ids)); 

En .NET 2.0, que es un poquito más difícil , ya que no hay tal sobrecarga. Por lo que necesita su propio método genérico:

public static string JoinArray<T>(string separator, T[] inputTypeArray) 
{ 
    string strRetValue = null; 
    System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>(); 

    for (int i = 0; i < inputTypeArray.Length; ++i) 
    { 
     string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture); 

     if (!string.IsNullOrEmpty(str)) 
     { 
      // SQL-Escape 
      // if (typeof(T) == typeof(string)) 
      // str = str.Replace("'", "''"); 

      ls.Add(str); 
     } // End if (!string.IsNullOrEmpty(str)) 

    } // Next i 

    strRetValue= string.Join(separator, ls.ToArray()); 
    ls.Clear(); 
    ls = null; 

    return strRetValue; 
} 

En .NET 3.5, puede utilizar los métodos de extensión:

public static class ArrayEx 
{ 

    public static string JoinArray<T>(this T[] inputTypeArray, string separator) 
    { 
     string strRetValue = null; 
     System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>(); 

     for (int i = 0; i < inputTypeArray.Length; ++i) 
     { 
      string str = System.Convert.ToString(inputTypeArray[i], System.Globalization.CultureInfo.InvariantCulture); 

      if (!string.IsNullOrEmpty(str)) 
      { 
       // SQL-Escape 
       // if (typeof(T) == typeof(string)) 
       // str = str.Replace("'", "''"); 

       ls.Add(str); 
      } // End if (!string.IsNullOrEmpty(str)) 

     } // Next i 

     strRetValue= string.Join(separator, ls.ToArray()); 
     ls.Clear(); 
     ls = null; 

     return strRetValue; 
    } 

} 

por lo que puede utilizar la extensión método JoinArray.

int[] ids = new int[] { 1, 2, 3 }; 
string strIdList = ids.JoinArray(","); 

También puede usar ese método de extensión en .NET 2.0, si agrega ExtensionAttribute a su código:

// you need this once (only), and it must be in this namespace 
namespace System.Runtime.CompilerServices 
{ 
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] 
    public sealed class ExtensionAttribute : Attribute {} 
} 
Cuestiones relacionadas