J'ai un tableau d'entiers:
int[] number = new int[] { 2,3,6,7 };
Quelle est la façon la plus simple de les convertir en une seule chaîne où les nombres sont séparés par un caractère (comme: "2,3,6,7"
)?
Je suis en C # et .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"
MODIFIER : depuis (au moins) .NET 4.5,
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());
est équivalent à:
var result = string.Join(",", ints);
MODIFIER :
Je vois plusieurs solutions annoncer l'utilisation de StringBuilder. Quelqu'un se plaint que la méthode Join doit prendre un argument IEnumerable.
Je vais vous décevoir :) String.Join nécessite un tableau pour une seule raison - les performances. La méthode Join doit connaître la taille des données pour préallouer efficacement la quantité de mémoire nécessaire.
Voici une partie de l'implémentation interne de la méthode 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]);
}
}
Je suis trop paresseux pour comparer les performances des méthodes suggérées. Mais quelque chose me dit que Join va gagner :)
Bien que l'OP spécifie .NET 3.5, les personnes qui souhaitent le faire dans .NET 2.0 avec C # 2 peuvent le faire:
string.Join(",", Array.ConvertAll<int, String>(ints, Convert.ToString));
Je trouve qu'il existe un certain nombre d'autres cas où l'utilisation des fonctions Convert.xxx est une alternative plus soignée à un lambda, bien qu'en C # 3 le lambda puisse aider à l'inférence de type.
Voici une version C # 3 assez compacte qui fonctionne avec .NET 2.0:
string.Join(",", Array.ConvertAll(ints, item => item.ToString()))
Un mélange des deux approches serait d'écrire une méthode d'extension sur IEnumerable <T> qui utilise un StringBuilder. Voici un exemple, avec différentes surcharges selon que vous souhaitez spécifier la transformation ou simplement compter sur ToString simple. J'ai nommé la méthode "JoinStrings" au lieu de "Join" pour éviter toute confusion avec l'autre type de jointure. Peut-être que quelqu'un peut trouver un meilleur nom :)
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());
Nous devons convertir chacun des éléments en String
avant de pouvoir les joindre, il est donc logique d'utiliser Select
et une expression lambda. Cela équivaut à map
dans certaines autres langues. Ensuite, nous devons reconvertir la collection de chaînes résultante en un tableau, car String.Join
Accepte uniquement un tableau de chaînes.
La ToArray()
est un peu moche je pense. String.Join
Devrait vraiment accepter IEnumerable<String>
, Il n'y a aucune raison de le restreindre aux seuls tableaux. C'est probablement parce que Join
est antérieur aux génériques, alors que les tableaux étaient le seul type de collection typée disponible.
Si votre tableau d'entiers peut être volumineux, vous obtiendrez de meilleures performances en utilisant un StringBuilder. Par exemple.:
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();
Edit: Lorsque j'ai posté cela, j'avais l'impression erronée que "StringBuilder.Append (valeur int)" a réussi en interne à ajouter la représentation sous forme de chaîne de la valeur entière sans créer d'objet chaîne. C'est faux: inspecter la méthode avec Reflector montre qu'elle ajoute simplement value.ToString ().
Par conséquent, la seule différence de performances potentielle est que cette technique évite la création d'un tableau et libère les chaînes pour le garbage collection un peu plus tôt. En pratique, cela ne fera aucune différence mesurable, j'ai donc voté positivement cette meilleure solution .
La question est de "la manière la plus simple de les convertir en une seule chaîne où le nombre est séparé par un caractère".
Le moyen le plus simple est:
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: Cela ne fonctionne que dans .NET 4.0+, j'ai manqué l'exigence .NET 3.5 la première fois que j'ai lu la question.
Dans .NET 4.0, la jointure de chaîne a une surcharge pour params object[]
, c'est donc aussi simple que:
int[] ids = new int[] { 1, 2, 3 };
string.Join(",", ids);
exemple
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));
Dans .NET 2.0, c'est un tout petit peu plus difficile, car il n'y a pas une telle surcharge. Vous avez donc besoin de votre propre méthode générique:
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;
}
Dans .NET 3.5, vous pouvez utiliser des méthodes d'extension:
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;
}
}
Vous pouvez donc utiliser la méthode d'extension JoinArray.
int[] ids = new int[] { 1, 2, 3 };
string strIdList = ids.JoinArray(",");
Vous pouvez également utiliser cette méthode d'extension dans .NET 2.0, si vous ajoutez ExtensionAttribute à votre code:
// 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 {}
}
Je suis d'accord avec l'expression lambda pour la lisibilité et la maintenabilité, mais ce ne sera pas toujours la meilleure option. L'inconvénient d'utiliser à la fois les approches IEnumerable/ToArray et StringBuilder est qu'ils doivent agrandir dynamiquement une liste d'éléments ou de caractères, car ils ne savent pas combien d'espace sera nécessaire pour la chaîne finale.
Si le cas rare où la vitesse est plus importante que la concision, ce qui suit est plus efficace.
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);
Je pensais aussi qu'il y avait un moyen plus simple. Je ne connais pas la performance, quelqu'un a une idée (théorique)?
Tu peux faire
ints.ToString(",")
ints.ToString("|")
ints.ToString(":")
Check-out
ToString délimité par séparateur pour tableau, liste, dictionnaire, IEnumerable générique