163 votes

IEnumerable<char> à chaîne

Je n'ai jamais tombé sur ça avant, mais j'ai maintenant et je suis surpris de voir que je ne trouve pas vraiment un moyen facile de convertir un IEnumerable<char> d'un string.

La meilleure façon que je peux penser à est de string str = new string(myEnumerable.ToArray());, mais, pour moi, il semble que cela permettrait de créer un nouveau char[], puis de créer un nouveau string , ce qui semble cher.

J'aurais pensé que ce serait une fonctionnalité commune intégrée dans le .NET framework quelque part. Est-il un moyen plus simple de faire cela?

Pour ceux que cela intéresse, la raison pour laquelle je voudrais utiliser ce qui est de l'utilisation de LINQ pour les chaînes de filtre:

string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());

171voto

Jeff Mercado Points 42075

Vous pouvez utiliser String.Concat().

var allowedString = String.Concat(
    inputString.Where(c => allowedChars.Contains(c))
);

Mise en garde: Cette approche aura une certaine incidence sur les performances. Il semble qu' String.Concat n'est pas le cas spécial des collections de caractères de sorte qu'il semble qu'il exécute comme si chaque personnage a été convertie en une chaîne ensuite concaténées (et la réalité). Sûr que cela vous donne un builtin pour accomplir cette tâche, mais il pourrait faire mieux.

Je ne pense pas qu'il existe des implémentations dans le cadre spécial de cas char de sorte que vous aurez à mettre en œuvre. Une simple boucle en ajoutant des caractères à un générateur de chaîne est assez simple à créer.


Voici quelques critères que j'ai pris sur une machine de dev et il semble à peu près juste.

1000000 itérations sur un 300 séquence de caractères sur un 32 bits version validée:

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();
}

88voto

Jodrell Points 14205

J'ai fait le sujet d' une autre question , mais de plus en plus et qui est en train de devenir une réponse directe à cette question.

J'ai fait quelques tests de performance de 3 méthodes simples de conversion d'un IEnumerable<char> d'un 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, ce qui est indiqué dans la question liée, pour 1000000 itérations de l' "Some reasonably small test data" - je obtenir de tels résultats,

1000000 itérations de "Concat" a pris 1597ms.

1000000 itérations de la "nouvelle chaîne" a pris 869ms.

1000000 itérations de "StringBuilder" a pris 748ms.

Cela me donne à penser qu'il n'y a pas de bonne raison de l'utiliser string.Concat pour cette tâche. Si vous voulez la simplicité d'utilisation de la nouvelle chaîne approche et si vous voulez améliorer les performances, utilisez le StringBuilder.

Je réserve mon affirmation, dans la pratique, toutes ces méthodes fonctionnent très bien, et cela pourrait être plus de l'optimisation.

23voto

MikeP Points 4823

Comme de .NET 4, de nombreuses méthodes string prendre IEnumerable comme arguments.

string.Concat(myEnumerable);

11voto

Adam Smith Points 131

Voici une nouvelle version de la classe StringBuilder réponse:

return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();

J'ai programmé ce en utilisant les mêmes tests que Jeff Mercado utilisé et a 1 seconde plus lent à travers 1 000 000 d'itérations sur la même 300 séquence de caractères (32 bits version release) que la 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 des accumulateurs alors ici vous allez.

10voto

hBGl Points 118

Mes données est contraire aux résultats de Jodrell posté. D'abord un coup d'oeil à l'extension des méthodes 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();
}

Mes résultats

Avec

  • STRLEN = 31
  • ITÉRATIONS = 1000000

Entrée

  • ((IEnumerable<char>)RandomString(STRLEN)).Reverse()

Résultats

  • Concat: 1x
  • Nouveau: 3x
  • StringBuilder: 3x

Entrée

  • ((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)

Résultats

  • Concat: 1x
  • Nouveau: 7x
  • StringBuilder: 7x

Entrée

  • ((IEnumerable<char>)RandomString(STRLEN)) (c'est juste une sortie)

Résultats

  • Concat: 0 ms
  • Nouveau: 2000 ms
  • StringBuilder: 2000 ms
  • Triste: 0 ms

J'ai couru ce sur un processeur Intel i5 760 ciblage .NET Framework 3.5.

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