Meilleure façon de répéter un caractère en C #

815

Quelle est la meilleure façon de générer une chaîne de \t'en C #

J'apprends le C # et j'expérimente différentes façons de dire la même chose.

Tabs(uint t)est une fonction qui renvoie une stringavec tquantité de \t« s

Par exemple, Tabs(3)retourne"\t\t\t"

Laquelle de ces trois façons de mettre en œuvre Tabs(uint numTabs)est la meilleure?

Bien sûr, cela dépend de ce que signifie le "meilleur".

  1. La version LINQ n'est que de deux lignes, ce qui est bien. Mais les appels à Répéter et à Agréger prennent-ils inutilement du temps / des ressources?

  2. La StringBuilderversion est très claire mais la StringBuilderclasse est-elle en quelque sorte plus lente?

  3. La stringversion est basique, ce qui signifie qu'elle est facile à comprendre.

  4. Cela n'a-t-il aucune importance? Sont-ils tous égaux?

Ce sont toutes des questions pour m'aider à mieux comprendre C #.

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat("\t", (int) numTabs);
    return (numTabs > 0) ? tabs.Aggregate((sum, next) => sum + next) : ""; 
}  

private string Tabs(uint numTabs)
{
    StringBuilder sb = new StringBuilder();
    for (uint i = 0; i < numTabs; i++)
        sb.Append("\t");

    return sb.ToString();
}  

private string Tabs(uint numTabs)
{
    string output = "";
    for (uint i = 0; i < numTabs; i++)
    {
        output += '\t';
    }
    return output; 
}
Alex Baranosky
la source

Réponses:

1492

Et ça:

string tabs = new String('\t', n);

nest le nombre de fois que vous souhaitez répéter la chaîne.

Ou mieux:

static string Tabs(int n)
{
    return new String('\t', n);
}
CMS
la source
2
est-il possible de répéter cela pour un mot? au lieu d'utiliser '\ t' comment utiliser "time"
asdfkjasdfjk
6
@ user1478137 Ou, mieux (aussi plus bas): ceci
Xynariz
161
string.Concat(Enumerable.Repeat("ab", 2));

Retour

"abab"

Et

string.Concat(Enumerable.Repeat("a", 2));

Retour

"aa"

de...

Existe-t-il une fonction intégrée pour répéter la chaîne ou le caractère dans .net?

Carter Medlin
la source
1
Améliorez-le en le faisant sans Linq et avec StruingBuilder!
Bitterblue
4
'' StringBuilder '' n'est pas nécessairement plus rapide stackoverflow.com/questions/585860/…
Schiavini
6
Ce n'est peut-être pas plus rapide, mais cela peut économiser sur les allocations de mémoire (pression) si vous spécifiez la capacité correcte à l'avance, et cela peut être aussi important que le micro-repère de profilage.
wekempf
1
var strRepeat = string.Concat (Enumerable.Repeat ("ABC", 1000000)); // 50ms
yongfa365
1
@Pharap string.Joinétait plus rapide dans l'exemple car ils utilisaient un délimiteur d'espace. string.Concatest approprié lorsqu'il n'y a pas de délimiteur.
Carter Medlin
124

Dans toutes les versions de .NET, vous pouvez répéter une chaîne ainsi:

public static string Repeat(string value, int count)
{
    return new StringBuilder(value.Length * count).Insert(0, value, count).ToString();
}

Pour répéter un personnage, new String('\t', count)c'est votre meilleur pari. Voir la réponse de @CMS .

Binoj Antony
la source
7
C'est de loin la performance la plus rapide pour String. D'autres méthodes créent trop de surcharge.
midspace
@midspace Savez-vous si quelqu'un a expliqué pourquoi les autres réponses sont pires? J'aurais supposé que le String.Concat natif serait tout aussi optimisé en interne que StringBuilder
Marie
@Marie L'article suivant explique certains des mérites. support.microsoft.com/en-au/help/306822/… Sinon, deux autres facteurs sont, StringBuilder autorise les chaînes et n'est pas limité à un simple caractère (bien que cela ne se rapporte pas à la question d'origine), et la chaîne. La réponse concat ci-dessus doit d'abord créer un tableau en utilisant Enumerable.Repeat. Comme je l'ai dit, ce sont des frais généraux inutiles.
midspace
J'avais supposé qu'il ne créerait pas un tableau en premier car il pourrait simplement itérer élément par élément. Merci pour le lien, je vais lui donner lecture!
Marie
63

La meilleure version est certainement d'utiliser la méthode intégrée:

string Tabs(int len) { return new string('\t', len); }

Parmi les autres solutions, préférez la plus simple; seulement si cela s'avère trop lent, essayez une solution plus efficace.

Si vous utilisez un StringBuilder et connaissez sa longueur résultante à l'avance, puis utilisez également un constructeur approprié, cela est beaucoup plus efficace car cela signifie qu'une seule allocation chronophage a lieu, et aucune copie inutile des données. Non-sens: bien sûr, le code ci-dessus est plus efficace.

Konrad Rudolph
la source
12
sb.Append ('\ t', len);
dan-gph
7
Mes repères se révèlent new string('\t', len)être entre 2x et 7x plus rapides que l' StringBuilderapproche. Pourquoi pensez-vous StringBuilderest plus efficace dans ce cas?
StriplingWarrior
6
@StriplingWarrior Merci d'avoir corrigé cela (après deux ans de présence ici, rien de moins!).
Konrad Rudolph
51

Méthodes d'extension:

public static string Repeat(this string s, int n)
{
    return new String(Enumerable.Range(0, n).SelectMany(x => s).ToArray());
}

public static string Repeat(this char c, int n)
{
    return new String(c, n);
}
Rodrick Chapman
la source
39
Il était une fois les gens utilisaient des boucles
prabhakaran
2
@prabhakaran Je suis d'accord mais l'avantage de Linq réside dans la communication; il est presque toujours trivial de réimplémenter une expression Linq en utilisant des constructions impératives.
Rodrick Chapman
10
Enumerable.Range(0, n).SelectMany(x => s)peut être remplacé par un simple Enumerable.Repeat(s, n).
Palec
5
@Palec Non, il ne peut pas. La SelectManyvolonté de chaque mannequin xdonne une séquence de charvaleurs (depuis les string simplémentations IEnumerable<char>), et toutes ces charséquences sont concaténées en une longue charséquence. Ce que vous proposez donnera plutôt un IEnumerable<string>. Ce n'est pas pareil.
Jeppe Stig Nielsen
2
J'avais tort, @JeppeStigNielsen. Merci pour l'information. Si je voulais vraiment utiliser Enumerable.Repeat, je concaténer les chaînes ensemble: string.Concat(Enumerable.Repeat(s, n)). Cela a déjà été publié auparavant .
Palec
40

Qu'en est-il de l'utilisation de la méthode d'extension?


public static class StringExtensions
{
   public static string Repeat(this char chatToRepeat, int repeat) {

       return new string(chatToRepeat,repeat);
   }
   public  static string Repeat(this string stringToRepeat,int repeat)
   {
       var builder = new StringBuilder(repeat*stringToRepeat.Length);
       for (int i = 0; i < repeat; i++) {
           builder.Append(stringToRepeat);
       }
       return builder.ToString();
   }
}

Vous pourriez alors écrire:

Debug.WriteLine('-'.Repeat(100)); // For Chars  
Debug.WriteLine("Hello".Repeat(100)); // For Strings

Notez qu'un test de performance d'utilisation de la version stringbuilder pour des caractères simples au lieu de chaînes vous donne une pénalité de préformance majeure: sur mon ordinateur, la différence de performances mesurées est de 1:20 entre: Debug.WriteLine ('-'. Repeat (1000000)) // version char et
Debug.WriteLine ("-". Repeat (1000000)) // version chaîne

Ronnie
la source
2
Les performances de la version chaîne peuvent être améliorées en utilisant StringBuilder.Insert(Int32, String, Int32), comme Binoj Anthony a répondu .
Palec
23

Que dis-tu de ça:

//Repeats a character specified number of times
public static string Repeat(char character,int numberOfIterations)
{
    return "".PadLeft(numberOfIterations, character);
}

//Call the Repeat method
Console.WriteLine(Repeat('\t',40));
Denys Wessels
la source
4
haha .. c'est ce à quoi je pouvais penser quand je suis tombé dans cette situation une fois. Mais personnellement, j'ai trouvé que new string('\t', 10)c'était la meilleure solution
shashwat
Cette astuce est également utilisée dans Essential C # 6.0 .
Programmeur orienté argent
22

Je sais que cette question a déjà cinq ans, mais il existe un moyen simple de répéter une chaîne qui fonctionne même dans .Net 2.0.

Pour répéter une chaîne:

string repeated = new String('+', 3).Replace("+", "Hello, ");

Retour

"Bonjour bonjour bonjour, "

Pour répéter une chaîne sous forme de tableau:

// Two line version.
string repeated = new String('+', 3).Replace("+", "Hello,");
string[] repeatedArray = repeated.Split(',');

// One line version.
string[] repeatedArray = new String('+', 3).Replace("+", "Hello,").Split(',');

Retour

{"Bonjour bonjour bonjour", ""}

Rester simple.

ChaimG
la source
19

Disons que vous voulez répéter '\ t' n nombre de fois, vous pouvez utiliser;

String.Empty.PadRight(n,'\t')
Amin
la source
1
Merci. C'est aussi très rapide. codereview.stackexchange.com/questions/36391/…
Sunsetquest
Je l'ai toujours fait de cette façon. Même s'il est enveloppé dans une méthode d'extension, il est plus simple que les autres implémentations publiées ici. Notez que OP ne voulait que répéter \ t, pas des chaînes.
Michael Ribbons
17

Votre premier exemple qui utilise Enumerable.Repeat:

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat(
                                 "\t", (int) numTabs);
    return (numTabs > 0) ? 
            tabs.Aggregate((sum, next) => sum + next) : ""; 
} 

peut être réécrit de manière plus compacte avec String.Concat:

private string Tabs(uint numTabs)
{       
    return String.Concat(Enumerable.Repeat("\t", (int) numTabs));
}
Rayon
la source
14

Utiliser String.Concatet Enumerable.Repeatqui sera moins cher que d'utiliserString.Join

public static Repeat(this String pattern, int count)
{
    return String.Concat(Enumerable.Repeat(pattern, count));
}
bradgonesurfing
la source
9
var str = new string(Enumerable.Repeat('\t', numTabs).ToArray());
wb
la source
4

La réponse dépend vraiment de la complexité que vous souhaitez. Par exemple, je veux décrire tous mes retraits avec une barre verticale, donc ma chaîne de retrait est déterminée comme suit:

return new string(Enumerable.Range(0, indentSize*indent).Select(
  n => n%4 == 0 ? '|' : ' ').ToArray());
Dmitri Nesteruk
la source
3

Et encore une autre méthode

new System.Text.StringBuilder().Append('\t', 100).ToString()
Artyom
la source
Passer la longueur de chaîne résultante au StringBuilderconstructeur enregistre la réallocation. Pourtant, c'est plus bavard et moins efficace que d'utiliser le stringconstructeur qui peut répéter un caractère donné, comme déjà montré dans la réponse acceptée.
Palec
3

Pour moi, c'est bien:

public static class Utils
{
    public static string LeftZerosFormatter(int zeros, int val)
    {
        string valstr = val.ToString();

        valstr = new string('0', zeros) + valstr;

        return valstr.Substring(valstr.Length - zeros, zeros);
    }
}
Ángel Ibáñez
la source
2

Vous pouvez créer une méthode d'extension

static class MyExtensions
{
    internal static string Repeat(this char c, int n)
    {
        return new string(c, n);
    }
}

Ensuite, vous pouvez l'utiliser comme ceci

Console.WriteLine('\t'.Repeat(10));
ivan
la source
1

Sans aucun doute, la réponse acceptée est le moyen le meilleur et le plus rapide de répéter un seul caractère.

La réponse de Binoj Anthony est un moyen simple et assez efficace de répéter une chaîne.

Cependant, si cela ne vous dérange pas un peu plus de code, vous pouvez utiliser ma technique de remplissage de tableau pour créer efficacement ces chaînes encore plus rapidement. Dans mes tests de comparaison, le code ci-dessous exécuté dans environ 35% du temps du code StringBuilder.Insert.

public static string Repeat(this string value, int count)
{
    var values = new char[count * value.Length];
    values.Fill(value.ToCharArray());
    return new string(values);
}

public static void Fill<T>(this T[] destinationArray, params T[] value)
{
    if (destinationArray == null)
    {
        throw new ArgumentNullException("destinationArray");
    }

    if (value.Length > destinationArray.Length)
    {
        throw new ArgumentException("Length of value array must not be more than length of destination");
    }

    // set the initial array value
    Array.Copy(value, destinationArray, value.Length);

    int copyLength, nextCopyLength;

    for (copyLength = value.Length; (nextCopyLength = copyLength << 1) < destinationArray.Length; copyLength = nextCopyLength)
    {
        Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
    }

    Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
}

Pour plus d'informations sur cette technique de remplissage de tableau, voir Méthode la plus rapide pour remplir un tableau avec une seule valeur

Grax32
la source
0

Essaye ça:

  1. Ajouter une référence Microsoft.VisualBasic
  2. Utilisation: String result = Microsoft.VisualBasic.Strings.StrDup (5, "hi");
  3. Dites-moi si cela marche pour vous.
Toso Pankovski
la source
Ajouter la dépendance à un autre assembly et la nécessité de le charger est déraisonnable dans la plupart des cas lorsque vous avez besoin d'une telle fonctionnalité. Pourtant, bon de savoir qu'il existe une telle chose dans .NET.
Palec
Il y a de nombreux avantages et inconvénients dans différents contextes, donc tout le monde devrait décider en fonction de la situation dans laquelle il se trouve.
Toso Pankovski
-1

Bien que très similaire à une suggestion précédente, j'aime rester simple et appliquer ce qui suit:

string MyFancyString = "*";
int strLength = 50;
System.Console.WriteLine(MyFancyString.PadRight(strLength, "*");

Standard .Net vraiment,

Porky
la source
Il ne fera qu'ajouter du rembourrage, ne se répète pas
levi