938 votes

Création d'une liste séparée par des virgules à partir de IList<string> ou IEnumerable<string>.

Quelle est la façon la plus propre de créer une liste de chaînes de caractères séparées par des virgules à partir d'un fichier de données d'entreprise ? IList<string> ou IEnumerable<string> ?

String.Join(...) fonctionne sur un string[] Il peut donc être fastidieux de travailler avec des types comme le IList<string> ou IEnumerable<string> ne peut pas être facilement converti en un tableau de chaînes de caractères.

5 votes

Oh... Oups. J'ai manqué l'ajout de la méthode d'extension ToArray en 3.5 : public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)

2 votes

Si vous êtes venu à cette question en cherchant un moyen d'écrire des CSV, il est bon de rappeler que le simple fait d'insérer des virgules entre les éléments est insuffisant et entraînera un échec dans le cas de guillemets et de virgules dans les données sources.

1610voto

Jon Skeet Points 692016

.NET 4+

IList<string> strings = new List<string>{"1","2","testing"};
string joined = string.Join(",", strings);

Solutions détaillées et pré .Net 4.0

IEnumerable<string> peut être converti en un tableau de chaînes de caractères très facilement avec LINQ (.NET 3.5) :

IEnumerable<string> strings = ...;
string[] array = strings.ToArray();

Il est assez facile d'écrire la méthode d'aide équivalente si vous en avez besoin :

public static T[] ToArray(IEnumerable<T> source)
{
    return new List<T>(source).ToArray();
}

Alors appelez-le comme ça :

IEnumerable<string> strings = ...;
string[] array = Helpers.ToArray(strings);

Vous pouvez alors appeler string.Join . Bien sûr, vous n'avez pas ont pour utiliser une méthode d'aide :

// C# 3 and .NET 3.5 way:
string joined = string.Join(",", strings.ToArray());
// C# 2 and .NET 2.0 way:
string joined = string.Join(",", new List<string>(strings).ToArray());

Ce dernier point est un peu difficile à comprendre :)

Il s'agit probablement de la manière la plus simple de procéder, et elle est également très performante. D'autres questions se posent quant aux performances exactes, notamment (mais pas exclusivement) les suivantes celui-ci .

Depuis la version 4.0 de .NET, il existe davantage de surcharges disponibles dans le module string.Join pour que tu puisses écrire :

string joined = string.Join(",", strings);

Beaucoup plus simple :)

0 votes

La méthode d'aide implique la création de deux listes inutiles. Est-ce vraiment la meilleure façon de résoudre le problème ? Pourquoi ne pas les concaténer vous-même dans une boucle foreach ?

4 votes

La méthode d'aide crée seulement un et un tableau. Le point est que le résultat doit être un tableau, pas une liste... et vous devez connaître la taille d'un tableau avant de commencer. Les meilleures pratiques disent que vous ne devriez pas énumérer une source plus d'une fois dans LINQ à moins que vous ne le deviez - elle pourrait faire toutes sortes de choses désagréables. Donc, il vous reste à lire dans des tampons et à redimensionner au fur et à mesure - ce qui est exactement ce que le programme List<T> fait. Pourquoi réinventer la roue ?

9 votes

Non, le point est que le résultat doit être une chaîne concaténée. Il n'est pas nécessaire de créer une nouvelle liste ou un nouveau tableau pour atteindre cet objectif. Ce genre de mentalité .NET me rend triste.

181voto

Xavier Poinas Points 8534

Pour information, la version .NET 4.0 de l'application string.Join() a quelques surcharges supplémentaires qui fonctionnent avec IEnumerable au lieu de simples tableaux, y compris un qui peut traiter n'importe quel type T :

public static string Join(string separator, IEnumerable<string> values)
public static string Join<T>(string separator, IEnumerable<T> values)

2 votes

Ceci appellera la méthode T.ToString() ?

0 votes

J'étais sur le point de commenter la réponse de Jon. Merci de l'avoir mentionné.

2 votes

Comment faire cela sur une propriété d'un objet ? (Ex : IEnumerable<Employee> et l'objet Employee a une propriété string .SSN, et obtenir une liste de SSN séparés par des virgules).

69voto

Daniel Fortunov Points 12044

Le moyen le plus simple que je vois pour le faire est d'utiliser le LINQ Aggregate méthode :

string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)

22 votes

Ce n'est pas seulement plus compliqué (IMO) que ToArray + Join, c'est aussi quelque peu inefficace - avec une grande séquence d'entrée, cela va commencer à fonctionner très mal.

36 votes

Quand même, c'est le plus joli.

2 votes

Vous pouvez alimenter Aggregate avec un StringBuilder seed, alors votre Aggregate Func devient Func<StringBuilder,string,StringBuider> . Ensuite, il suffit d'appeler ToString() sur le StringBuilder retourné. Bien sûr, ce n'est pas aussi joli :)

33voto

Dan VanWinkle Points 463

Je pense que la manière la plus propre de créer une liste de valeurs de chaînes séparées par des virgules est simplement :

string.Join<string>(",", stringEnumerable);

Voici un exemple complet :

IEnumerable<string> stringEnumerable= new List<string>();
stringList.Add("Comma");
stringList.Add("Separated");

string.Join<string>(",", stringEnumerable);

Il n'est pas nécessaire de créer une fonction d'aide, celle-ci est intégrée à .NET 4.0 et plus.

4 votes

Notez que ceci est applicable à partir de .NET 4 (comme Xavier l'a souligné dans sa réponse).

0 votes

Du point de vue d'un débutant en .NET 4 avec moins d'un mois d'expérience, cette réponse était une belle combinaison de justesse et de concision.

8voto

David Clarke Points 3165

J'arrive un peu tard dans cette discussion, mais voici ma contribution. J'ai un IList<Guid> OrderIds pour être converti en chaîne CSV mais ce qui suit est générique et fonctionne sans modification avec d'autres types :

string csv = OrderIds.Aggregate(new StringBuilder(),
             (sb, v) => sb.Append(v).Append(","),
             sb => {if (0 < sb.Length) sb.Length--; return sb.ToString();});

Court et efficace, utilise StringBuilder pour construire une nouvelle chaîne, réduit la longueur de StringBuilder d'une unité pour supprimer la dernière virgule et retourne une chaîne CSV.

Je l'ai mis à jour pour utiliser plusieurs Append() pour ajouter la chaîne + la virgule. D'après les commentaires de James, j'ai utilisé Reflector pour jeter un coup d'œil sur les éléments suivants StringBuilder.AppendFormat() . Il s'avère que AppendFormat() utilise un StringBuilder pour construire la chaîne de format, ce qui le rend moins efficace dans ce contexte que l'utilisation de plusieurs chaînes de format. Appends() 's.

0 votes

Gazumped, merci Xavier, je n'étais pas au courant de cette mise à jour dans .Net4. Le projet sur lequel je travaille n'a pas encore fait le saut, je vais donc continuer à utiliser mon exemple maintenant piéton en attendant.

2 votes

Cela échouera avec une source IEnumerable à zéro élément. sb.Length-- a besoin d'une vérification des limites.

0 votes

Bien vu, merci James, dans le contexte où je l'utilise, je suis "garanti" d'avoir au moins un OrderId. J'ai mis à jour l'exemple et mon propre code pour inclure la vérification des limites (juste pour être sûr).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X