Der beste Weg, um ein Zeichen in C # zu wiederholen

814

Was ist der beste Weg, um eine Zeichenfolge von \t's in C # zu generieren?

Ich lerne C # und experimentiere mit verschiedenen Arten, dasselbe zu sagen.

Tabs(uint t)ist eine Funktion, die a stringmit der tAnzahl von \t's zurückgibt

Zum Beispiel Tabs(3)kehrt zurück"\t\t\t"

Welche dieser drei Implementierungsmethoden Tabs(uint numTabs)ist die beste?

Das hängt natürlich davon ab, was "am besten" bedeutet.

  1. Die LINQ-Version besteht nur aus zwei Zeilen, was sehr schön ist. Aber sind die Aufrufe zum Wiederholen und Aggregieren unnötig zeit- und ressourcenintensiv?

  2. Die StringBuilderVersion ist sehr klar, aber ist die StringBuilderKlasse irgendwie langsamer?

  3. Die stringVersion ist einfach, was bedeutet, dass sie leicht zu verstehen ist.

  4. Ist das überhaupt nicht wichtig? Sind sie alle gleich?

Dies sind alles Fragen, die mir helfen sollen, ein besseres Gefühl für C # zu bekommen.

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
quelle

Antworten:

1491

Was ist damit:

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

Wo nmöchten Sie die Zeichenfolge wiederholen?

Oder besser:

static string Tabs(int n)
{
    return new String('\t', n);
}
CMS
quelle
2
Gibt es eine Möglichkeit, dies für ein Wort zu wiederholen? anstatt '\ t' zu verwenden, wie man "Zeit" verwendet
asdfkjasdfjk
6
@ user1478137 Oder besser (auch weiter unten): dies
Xynariz
161
string.Concat(Enumerable.Repeat("ab", 2));

Kehrt zurück

"abab"

Und

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

Kehrt zurück

"aa"

von...

Gibt es eine integrierte Funktion zum Wiederholen von Zeichenfolgen oder Zeichen in .net?

Carter Medlin
quelle
1
Mach es besser, indem du es ohne Linq und mit machst StruingBuilder!
Bitterblue
4
StringBuilder ist nicht unbedingt schneller stackoverflow.com/questions/585860/…
Schiavini
6
Es ist möglicherweise nicht schneller, spart jedoch Speicherzuweisungen (Druck), wenn Sie im Voraus die richtige Kapazität angeben. Dies kann ebenso wichtig sein wie der Mikro-Benchmark für die Profilerstellung.
wekempf
1
var strRepeat = string.Concat (Enumerable.Repeat ("ABC", 1000000)); // 50ms
yongfa365
1
@Pharap string.Joinwar im Beispiel schneller, da ein Leerzeichen verwendet wurde. string.Concatist angemessen, wenn kein Trennzeichen vorhanden ist.
Carter Medlin
124

In allen Versionen von .NET können Sie eine Zeichenfolge folgendermaßen wiederholen:

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

Einen Charakter zu wiederholen, new String('\t', count)ist die beste Wahl. Siehe die Antwort von @CMS .

Binoj Antony
quelle
7
Dies ist bei weitem die schnellste Leistung für String. Andere Methoden verursachen zu viel Overhead.
Midspace
@midspace Weißt du, ob jemand erklärt hat, warum die anderen Antworten schlechter sind? Ich hätte angenommen, dass der native String.Concat intern genauso optimiert wäre wie StringBuilder
Marie
@ Marie Der folgende Artikel erklärt einige der Vorzüge. support.microsoft.com/en-au/help/306822/… Andernfalls sind zwei weitere Faktoren zu berücksichtigen: StringBuilder erlaubt Zeichenfolgen und ist nicht nur auf ein Zeichen (obwohl dies nicht die ursprüngliche Frage betrifft) und die Zeichenfolge beschränkt. Die obige Concat-Antwort muss zuerst mit Enumerable.Repeat ein Array erstellen. Wie gesagt, es ist unnötig Overhead.
Midspace
Ich hatte angenommen, dass es nicht zuerst ein Array erstellen würde, da es nur Element für Element iterieren könnte. Vielen Dank für den Link, ich werde es lesen!
Marie
63

Die beste Version ist sicherlich die eingebaute Methode:

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

Von den anderen Lösungen bevorzugen Sie die einfachste; Nur wenn sich dies als zu langsam herausstellt, streben Sie nach einer effizienteren Lösung.

Wenn Sie a verwenden StringBuilderund die resultierende Länge im Voraus kennen, dann verwenden Sie auch einen geeigneten Konstruktor. Dies ist viel effizienter, da nur eine zeitaufwändige Zuordnung erfolgt und keine unnötigen Daten kopiert werden. Unsinn: Natürlich ist der obige Code effizienter.

Konrad Rudolph
quelle
12
sb.Append ('\ t', len);
Dan-Gph
7
Meine Benchmarks sind new string('\t', len)zwischen 2x und 7x schneller als der StringBuilderAnsatz. Warum ist das Ihrer Meinung StringBuildernach in diesem Fall effizienter?
StriplingWarrior
6
@StriplingWarrior Danke, dass du das korrigiert hast (nachdem es zwei Jahre hier gestanden hat, nicht weniger!).
Konrad Rudolph
51

Erweiterungsmethoden:

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
quelle
39
Es war einmal, als Menschen Loops benutzten
Prabhakaran
2
@ Prabhakaran Ich stimme zu, aber der Vorteil von Linq liegt in der Kommunikation; Es ist fast immer trivial, einen Linq-Ausdruck mit imperativen Konstrukten neu zu implementieren.
Rodrick Chapman
10
Enumerable.Range(0, n).SelectMany(x => s)kann durch eine einfache ersetzt werden Enumerable.Repeat(s, n).
Palec
5
@ Palec Nein, das kann es nicht. Der SelectManyWille für jeden einzelnen Dummy xgibt eine Folge von charWerten an (seit den string sImplementierungen IEnumerable<char>), und alle diese charFolgen werden zu einer langen charFolge verkettet . Was Sie vorschlagen, wird stattdessen eine geben IEnumerable<string>. Es ist nicht das Gleiche.
Jeppe Stig Nielsen
2
Ich habe mich geirrt, @JeppeStigNielsen. Danke für die Warnung. Wenn ich es wirklich benutzen wollteEnumerable.Repeat musste ich die Zeichenfolgen miteinander verketten : string.Concat(Enumerable.Repeat(s, n)). Dies wurde bereits zuvor gepostet .
Palec
40

Was ist mit der Erweiterungsmethode?


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

Sie könnten dann schreiben:

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

Beachten Sie, dass ein Leistungstest der Verwendung der Stringbuilder-Version für einfache Zeichen anstelle von Zeichenfolgen zu einer erheblichen Leistungsminderung führt: Auf meinem Computer beträgt der Unterschied in der gemessenen Leistung 1:20 zwischen: Debug.WriteLine ('-'. Repeat (1000000)) // char version und
Debug.WriteLine ("-". Repeat (1000000)) // string version

Ronnie
quelle
2
Die Leistung der String-Version kann durch Verwendung von verbessert werden StringBuilder.Insert(Int32, String, Int32), wie Binoj Anthony antwortete .
Palec
23

Wie wäre es damit:

//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));
Verweigert Wessels
quelle
4
haha .. daran konnte ich denken, als ich einmal in diese Situation geriet. Aber persönlich fand new string('\t', 10)ich die beste Lösung
Shashwat
Dieser Trick wird auch in Essential C # 6.0 verwendet .
Geldorientierter Programmierer
22

Ich weiß, dass diese Frage bereits fünf Jahre alt ist, aber es gibt eine einfache Möglichkeit, eine Zeichenfolge zu wiederholen, die sogar in .Net 2.0 funktioniert.

So wiederholen Sie eine Zeichenfolge:

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

Kehrt zurück

"Hallo hallo hallo, "

So wiederholen Sie eine Zeichenfolge als 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(',');

Kehrt zurück

{"Hallo hallo hallo", ""}

Halte es einfach.

ChaimG
quelle
19

Angenommen, Sie möchten '\ t' n so oft wiederholen, wie Sie verwenden können.

String.Empty.PadRight(n,'\t')
Amin
quelle
1
Vielen Dank. Das geht auch sehr schnell. codereview.stackexchange.com/questions/36391/...
Sunsetquest
Ich habe es immer so gemacht. Selbst wenn es in eine Erweiterungsmethode eingeschlossen ist, ist es einfacher als andere hier veröffentlichte Implementierungen. Beachten Sie, dass OP nur \ t wiederholen wollte, keine Zeichenfolgen.
Michael Ribbons
17

Ihr erstes Beispiel, das verwendet Enumerable.Repeat:

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

kann kompakter umgeschrieben werden mit String.Concat:

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

Verwenden String.Concatund Enumerable.Repeatdas ist billiger als verwendenString.Join

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

Die Antwort hängt wirklich von der gewünschten Komplexität ab. Zum Beispiel möchte ich alle meine Einrückungen mit einem vertikalen Balken umreißen, sodass meine Einrückungszeichenfolge wie folgt bestimmt wird:

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

Und noch eine andere Methode

new System.Text.StringBuilder().Append('\t', 100).ToString()
Artyom
quelle
Durch Übergeben der resultierenden Zeichenfolgenlänge an den StringBuilderKonstruktor wird eine Neuzuweisung gespeichert. Dies ist jedoch gesprächiger und weniger effizient als die Verwendung des stringKonstruktors, der ein bestimmtes Zeichen wiederholen kann, wie bereits in der akzeptierten Antwort gezeigt.
Palec
3

Für mich ist in Ordnung:

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
quelle
2

Sie können eine Erweiterungsmethode erstellen

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

Dann können Sie es so verwenden

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

Ohne Zweifel ist die akzeptierte Antwort der beste und schnellste Weg, um ein einzelnes Zeichen zu wiederholen.

Die Antwort von Binoj Anthony ist eine einfache und recht effiziente Möglichkeit, eine Zeichenfolge zu wiederholen.

Wenn Ihnen jedoch etwas mehr Code nichts ausmacht, können Sie meine Array-Fülltechnik verwenden, um diese Zeichenfolgen noch schneller effizient zu erstellen. In meinen Vergleichstests wurde der folgende Code in etwa 35% der Zeit des StringBuilder.Insert-Codes ausgeführt.

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

Weitere Informationen zu dieser Array-Fülltechnik finden Sie unter Schnellste Methode zum Füllen eines Arrays mit einem einzelnen Wert

Grax32
quelle
0

Versuche dies:

  1. Fügen Sie die Microsoft.VisualBasic-Referenz hinzu
  2. Verwendung: String result = Microsoft.VisualBasic.Strings.StrDup (5, "hi");
  3. Lassen Sie mich wissen, ob es für Sie funktioniert.
Toso Pankovski
quelle
Das Hinzufügen der Abhängigkeit von einer anderen Baugruppe und die Notwendigkeit, diese zu laden, ist in den meisten Fällen nicht zumutbar, wenn Sie solche Funktionen benötigen. Gut zu wissen, dass es so etwas in .NET gibt.
Palec
Es gibt viele Vor- und Nachteile in unterschiedlichen Kontexten, daher sollte jeder entscheiden, in
welcher
-1

Obwohl ich einem früheren Vorschlag sehr ähnlich bin, möchte ich ihn einfach halten und Folgendes anwenden:

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

Standard .Net wirklich,

Schweinefleisch
quelle
Es wird nur Polsterung hinzugefügt, nicht wiederholt
Levi