Il modo migliore per ripetere un personaggio in C #


815

Qual è il modo migliore per generare una stringa di \t's in C #

Sto imparando C # e sto sperimentando modi diversi di dire la stessa cosa.

Tabs(uint t)è una funzione che restituisce una stringcon tquantità di \ts'

Ad esempio, Tabs(3)ritorna"\t\t\t"

Quale di questi tre modi di attuazione Tabs(uint numTabs)è il migliore?

Naturalmente ciò dipende dal significato di "migliore".

  1. La versione LINQ ha solo due righe, il che è carino. Ma le chiamate per ripetere e aggregare inutilmente richiedono tempo / risorse?

  2. La StringBuilderversione è molto chiara ma la StringBuilderclasse è in qualche modo più lenta?

  3. La stringversione è di base, il che significa che è facile da capire.

  4. Non importa affatto? Sono tutti uguali?

Queste sono tutte domande per aiutarmi a capire meglio 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; 
}

Risposte:


1492

Che dire di questo:

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

Dov'è nil numero di volte in cui desideri ripetere la stringa.

O meglio:

static string Tabs(int n)
{
    return new String('\t', n);
}

2
c'è un modo per ripetere questo per una parola? invece di usare '\ t' come usare "time"
asdfkjasdfjk

6
@ user1478137 O meglio (anche più in basso): questo
Xynariz

161
string.Concat(Enumerable.Repeat("ab", 2));

ritorna

"ABAB"

E

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

ritorna

"aa"

a partire dal...

Esiste una funzione integrata per ripetere string o char in .net?


1
Renderlo migliore facendolo senza Linq e con StruingBuilder!
Bitterblue,

4
'' StringBuilder '' non è necessariamente più veloce stackoverflow.com/questions/585860/…
Schiavini

6
Potrebbe non essere più veloce, ma può risparmiare sulle allocazioni di memoria (pressione) se si specifica la capacità corretta in anticipo e questo può essere importante quanto il micro benchmark di profilare questo.
wekempf,

1
var strRepeat = string.Concat (Enumerable.Repeat ("ABC", 1000000)); // 50ms
yongfa365

1
@Pharap è string.Joinstato più veloce nell'esempio perché utilizzava un delimitatore di spazio. string.Concatè appropriato quando non è presente alcun delimitatore.
Carter Medlin,

124

In tutte le versioni di .NET, è possibile ripetere una stringa in questo modo:

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

Ripetere un personaggio, new String('\t', count)è la soluzione migliore. Vedi la risposta di @CMS .


7
Questa è di gran lunga la prestazione più veloce per String. Altri metodi creano un sovraccarico eccessivo.
metà spazio

@midspace Sai se qualcuno ha spiegato perché le altre risposte sono peggiori? Avrei supposto che String.Concat nativo fosse ottimizzato internamente come StringBuilder
Marie

@Marie Il seguente articolo spiega alcuni dei meriti. support.microsoft.com/en-au/help/306822/… Altrimenti altri due fattori sono, StringBuilder consente le stringhe e non si limita a un solo carattere (anche se non si riferisce alla domanda originale) e alla stringa. La risposta concat sopra deve creare prima un array usando Enumerable.Repeat. Come ho detto, è inutile sovraccarico.
metà spazio

Avevo supposto che non avrebbe creato prima un array perché poteva solo iterare articolo per articolo. Grazie per il link, lo darò una lettura!
Marie

63

La versione migliore è sicuramente quella di utilizzare il modo integrato:

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

Tra le altre soluzioni, preferisci la più semplice; solo se questo si sta rivelando troppo lento, cerca una soluzione più efficiente.

Se usi a StringBuilder e conosci in anticipo la sua lunghezza risultante, quindi usi anche un costruttore appropriato, questo è molto più efficiente perché significa che ha luogo solo un'allocazione che richiede tempo e nessuna copia non necessaria di dati. Sciocchezze: ovviamente il codice sopra è più efficiente.


12
sb.Append ('\ t', len);
dan-gph,

7
I miei parametri di riferimento stanno dimostrando new string('\t', len)di essere tra 2 e 7 volte più veloci StringBuilderdell'approccio. Perché pensi che StringBuildersia più efficiente in questo caso?
StriplingWarrior il

6
@StriplingWarrior Grazie per averlo corretto (dopo essere stato qui per due anni, non meno!).
Konrad Rudolph,

51

Metodi di estensione:

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

39
C'era una volta la gente che usava i loop
prabhakaran,

2
@prabhakaran Sono d'accordo, ma il vantaggio di Linq è nella comunicazione; è quasi sempre banale reimplementare un'espressione di Linq usando costrutti imperativi.
Rodrick Chapman,

10
Enumerable.Range(0, n).SelectMany(x => s)può essere sostituito da un semplice Enumerable.Repeat(s, n).
Palec,

5
@Palec No non può. La SelectManyvolontà di ogni singolo manichino xfornisce una sequenza di charvalori (dal momento che gli string sattrezzi IEnumerable<char>), e tutte quelle charsequenze sono concatenate in un'unica lunga charsequenza. Quello che suggerirai invece darà un IEnumerable<string>. Non é la stessa cosa.
Jeppe Stig Nielsen,

2
Ho sbagliato, @JeppeStigNielsen. Grazie per il testa a testa. Se volevo davvero usare Enumerable.Repeat, avrei dovuto concatenare le stringhe: string.Concat(Enumerable.Repeat(s, n)). Questo è già stato pubblicato prima .
Palec,

40

Che dire dell'utilizzo del metodo di estensione?


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

È quindi possibile scrivere:

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

Si noti che un test delle prestazioni dell'utilizzo della versione stringbuilder per caratteri semplici anziché stringhe offre una penalità di preformance maggiore: sul mio computer la differenza nelle prestazioni misurate è 1:20 tra: Debug.WriteLine ('-'. Repeat (1000000)) // versione char e
Debug.WriteLine ("-". Repeat (1000000)) // versione stringa


2
Le prestazioni della versione stringa possono essere migliorate utilizzando StringBuilder.Insert(Int32, String, Int32), come ha risposto Binoj Anthony .
Palec,

23

Cosa ne pensi di questo:

//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));

4
haha .. questo è quello che mi viene in mente quando sono caduto in questa situazione una volta. Ma personalmente ho scoperto new string('\t', 10)di essere la soluzione migliore
shashwat il

Questo trucco è utilizzato anche in Essential C # 6.0 .
Programmatore orientato al denaro il

22

So che questa domanda ha già cinque anni ma c'è un modo semplice per ripetere una stringa che funziona anche in .Net 2.0.

Per ripetere una stringa:

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

ritorna

"Ciao ciao ciao, "

Per ripetere una stringa come un array:

// 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(',');

ritorna

{"Ciao ciao ciao", ""}

Mantienilo semplice.



17

Il tuo primo esempio che utilizza Enumerable.Repeat:

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

può essere riscritto in modo più compatto con String.Concat :

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

14

Utilizzo String.Concate Enumerable.Repeatche sarà meno costoso dell'utilizzoString.Join

public static Repeat(this String pattern, int count)
{
    return String.Concat(Enumerable.Repeat(pattern, count));
}

9
var str = new string(Enumerable.Repeat('\t', numTabs).ToArray());

4

La risposta dipende davvero dalla complessità che desideri. Ad esempio, voglio delineare tutti i miei rientri con una barra verticale, quindi la mia stringa di rientro è determinata come segue:

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

3

E ancora un altro metodo

new System.Text.StringBuilder().Append('\t', 100).ToString()

Passare la lunghezza della stringa risultante al StringBuildercostruttore salva la riallocazione. Tuttavia, questo è più loquace e meno efficiente rispetto all'utilizzo del stringcostruttore in grado di ripetere un determinato personaggio, come già mostrato nella risposta accettata.
Palec,

3

Per me va bene:

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

2

È possibile creare un metodo di estensione

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

Quindi puoi usarlo in questo modo

Console.WriteLine('\t'.Repeat(10));

1

Senza dubbio la risposta accettata è il modo migliore e più veloce per ripetere un singolo personaggio.

La risposta di Binoj Anthony è un modo semplice ed abbastanza efficace per ripetere una stringa.

Tuttavia, se non ti dispiace un po 'più di codice, puoi utilizzare la mia tecnica di riempimento dell'array per creare in modo efficiente queste stringhe ancora più velocemente. Nei miei test di confronto, il codice seguente è stato eseguito in circa il 35% delle volte del codice 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);
}

Per ulteriori informazioni su questa tecnica di riempimento di array, vedere Il modo più veloce per riempire un array con un singolo valore


0

Prova questo:

  1. Aggiungi riferimento Microsoft.VisualBasic
  2. Usa: String result = Microsoft.VisualBasic.Strings.StrDup (5, "ciao");
  3. Fammi sapere se funziona per te.

L'aggiunta di dipendenza da un altro assembly e la necessità di caricarlo è irragionevole nella maggior parte dei casi quando è necessaria tale funzionalità. Tuttavia, è bello sapere che esiste una cosa del genere in .NET.
Palec,

Ci sono molti pro e contro in contesti diversi, quindi ognuno dovrebbe decidere a seconda della situazione in cui si trova.
Toso Pankovski,

-1

Anche se molto simile a un suggerimento precedente, mi piace mantenerlo semplice e applicare quanto segue:

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

Standard .Net davvero,


Aggiungerà solo un'imbottitura, non si ripete
levi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.