Je ne suis jamais tombé sur cela auparavant, mais je suis surpris de ne pas trouver un moyen très facile de convertir un IEnumerable<char>
En un string
.
La meilleure façon de penser est string str = new string(myEnumerable.ToArray());
, mais pour moi, il me semble que cela créerait un nouveau char[]
, Puis créerait un nouveau string
, ce qui semble cher.
J'aurais pensé qu'il s'agirait d'une fonctionnalité commune intégrée quelque part au framework .NET. Y a-t-il un moyen plus simple de faire cela?
Pour ceux que ça intéresse, je voudrais utiliser ceci pour utiliser LINQ afin de filtrer les chaînes:
string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());
Vous pouvez utiliser String.Concat()
.
var allowedString = String.Concat(
inputString.Where(c => allowedChars.Contains(c))
);
Mise en garde : Cette approche aura des conséquences sur les performances. String.Concat
ne contient pas de casse particulière dans les collections de caractères, il fonctionne donc comme si chaque caractère avait été converti en chaîne puis concaténé comme indiqué dans la documentation (et c’est le cas). Bien sûr, cela vous donne un moyen intégré pour accomplir cette tâche, mais cela pourrait être mieux fait.
Je ne pense pas qu'il y ait d'implémentations dans le cadre qui ferait un cas spécial char
donc vous devrez l'implémenter. Une simple boucle ajoutant des caractères à un constructeur de chaînes est assez simple à créer.
Voici quelques points de repère que j'ai pris sur une machine de développement et il semble à peu près correct.
1000000 itérations sur une séquence de 300 caractères sur une version 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<char> seq = Enumerable.Repeat('a', 300);
static string ToArrayString(IEnumerable<char> charSequence)
{
return new String(charSequence.ToArray());
}
static string Concat(IEnumerable<char> charSequence)
{
return String.Concat(charSequence);
}
static string StringBuilderChars(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c);
}
return sb.ToString();
}
static string StringBuilderStrings(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c.ToString());
}
return sb.ToString();
}
Edité pour l'édition de .Net Core 2.1
En répétant le test pour la sortie de .Net Core 2.1, j'obtiens des résultats comme celui-ci
1 000 itérations de "Concat" ont pris 842ms.
1000000 itérations de "new String" ont pris 1009ms.
1000000 itérations de "qn" ont pris 902ms.
En bref, si vous utilisez .Net Core 2.1 ou une version ultérieure, Concat
est roi.
Voir article de blog MS pour plus de détails.
J'ai fait de ce sujet le sujet de ne autre question mais de plus en plus, cela devient une réponse directe à cette question.
J'ai effectué des tests de performance de 3 méthodes simples de conversion d'un IEnumerable<char>
à string
, ces méthodes sont
nouvelle chaîne
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();
Dans mes tests, cela est détaillé dans le question liée , pour 1000000
itérations de "Some reasonably small test data"
J'obtiens des résultats comme celui-ci,
1000000 itérations de "Concat" a pris 1597ms.
1000000 itérations de "nouvelle chaîne" a pris 869ms.
1000000 itérations de "StringBuilder" ont pris 748ms.
Cela me suggère qu'il n'y a pas de bonne raison d'utiliser string.Concat
pour cette tâche. Si vous voulez la simplicité, utilisez l’approche Nouvelle chaîne et si vous voulez des performances, utilisez le StringBuilder .
J'avertirais de mon assertion, dans la pratique toutes ces méthodes fonctionnent bien, et tout cela pourrait être sur l'optimisation.
À partir de .NET 4, de nombreuses méthodes de chaîne utilisent IEnumerable en tant qu'arguments.
string.Concat(myEnumerable);
Mes données sont contraires aux résultats publiés par Jodrell. Jetez d'abord un coup d'œil aux méthodes d'extension que j'utilise:
public static string AsStringConcat(this IEnumerable<char> characters)
{
return String.Concat(characters);
}
public static string AsStringNew(this IEnumerable<char> characters)
{
return new String(characters.ToArray());
}
public static string AsStringSb(this IEnumerable<char> characters)
{
StringBuilder sb = new StringBuilder();
foreach (char c in characters)
{
sb.Append(c);
}
return sb.ToString();
}
avec
Entrée
((IEnumerable<char>)RandomString(STRLEN)).Reverse()
Résultats
Entrée
((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)
Résultats
Entrée
((IEnumerable<char>)RandomString(STRLEN))
(ceci est juste un upcast)Résultats
Je l'ai exécuté sur un Intel i5 760 ciblant .NET Framework 3.5.
Une autre possibilité est d'utiliser
string.Join("", myEnumerable);
Je n'ai pas mesuré la performance.
Voici une version plus succincte de la réponse de StringBuilder:
return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();
J'ai chronométré ceci en utilisant les mêmes tests que ceux utilisés par Jeff Mercado, ce qui a été plus lent d'une seconde sur 1 000 000 d'itérations sur la même séquence de 300 caractères (génération de version 32 bits) que le plus explicite:
static string StringBuilderChars(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c);
}
return sb.ToString();
}
Donc, si vous êtes un fan d'accumulateurs, alors vous y êtes.