Tengo una matriz de enteros:
int[] number = new int[] { 2,3,6,7 };
¿Cuál es la forma más fácil de convertirlos 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.
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 : A partir de (al menos) .NET 4.5,
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());
es equivalente a:
var result = string.Join(",", ints);
EDITAR :
Veo varias soluciones que anuncian el uso de StringBuilder. Alguien se queja de que el método Join debería tomar un argumento IEnumerable.
Te voy a decepcionar :) String.Join requiere una matriz por una única razón: rendimiento. El método de unión necesita conocer el tamaño de los datos para preasignar eficazmente la cantidad de memoria necesaria.
Aquí hay 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 vago para comparar el rendimiento de los métodos sugeridos. Pero algo me dice que Join ganará :)
using System.Linq;
es requerido.
Aunque el OP especificó .NET 3.5, las personas que quieran hacer esto en .NET 2.0 con C # 2 pueden hacer esto:
string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));
Encuentro que hay otros casos en los que el uso de las funciones Convert.xxx es una alternativa más ordenada a una lambda, aunque en C # 3 la lambda podría ayudar a la inferencia de tipos.
Una versión bastante compacta de C # 3 que funciona con .NET 2.0 es la siguiente:
string.Join(",", Array.ConvertAll(ints, item => item.ToString()))
Una mezcla de los dos enfoques sería escribir un método de extensión en IEnumerable <T> que usa 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. Quizás alguien pueda pensar en 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"), ","));
}
}
String.Join(";", number.Select(item => item.ToString()).ToArray());
Tenemos que convertir cada uno de los elementos a String
antes de poder unirlos, por lo que tiene sentido usar Select
una expresión lambda. Esto es equivalente a map
en algunos otros idiomas. Luego tenemos que convertir la colección resultante de cadenas de nuevo en una matriz, porque String.Join
solo acepta una matriz de cadenas.
El ToArray()
es un poco feo que pienso. String.Join
realmente debería aceptar IEnumerable<String>
, no hay razón para restringirlo solo a matrices. Esto probablemente se deba a que Join
es anterior a los genéricos, cuando las matrices eran el único tipo de colección con tipo disponible.
Si su matriz de números enteros puede ser grande, obtendrá un mejor rendimiento con StringBuilder. P.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é esto, tenía la impresión errónea de que "StringBuilder.Append (int value)" logró agregar internamente 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 un poco antes. En la práctica, esto no hará ninguna diferencia medible, así que voté a favor de esta mejor solución .
La pregunta es cuál es la "forma más sencilla de convertirlos en una sola cadena donde los números están separados 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
EDITAR: Esto solo funciona en .NET 4.0+, me perdí el requisito de .NET 3.5 la primera vez que leí la pregunta.
Estoy de acuerdo con la expresión lambda por legibilidad y mantenibilidad, pero no siempre será la mejor opción. La desventaja de usar 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 se da el raro caso de que la velocidad sea 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);
ints.Aggregate("", ( str, n ) => str +","+ n ).Substring(1);
También pensé que había una forma más sencilla. No sé sobre rendimiento, ¿alguien tiene alguna idea (teórica)?
Substring(1)
para arreglar eso (era de memoria).
En .NET 4.0, la combinación de cadenas tiene una sobrecarga para 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, es un poquito más difícil, ya que no existe tal sobrecarga. Entonces necesitas tu 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 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;
}
}
Entonces puede usar el método de extensión 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 {}
}
Tu puedes hacer
ints.ToString(",")
ints.ToString("|")
ints.ToString(":")
Revisa
ToString delimitado por separador para matriz, lista, diccionario, IEnumerable genérico
.NET 4.0
ahí, existen métodos que toman una matriz de objetos y un IEnumerable para que pueda hacerlostring.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.