Kann ich eine Zeichenfolge (in C #) „multiplizieren“?

136

Angenommen, ich habe eine Zeichenfolge, zum Beispiel

string snip =  "</li></ul>";

Ich möchte es grundsätzlich mehrmals schreiben, abhängig von einem ganzzahligen Wert.

string snip =  "</li></ul>";
int multiplier = 2;

// TODO: magic code to do this 
// snip * multiplier = "</li></ul></li></ul>";

EDIT: Ich weiß, dass ich leicht meine eigene Funktion schreiben kann, um dies zu implementieren. Ich habe mich nur gefragt, ob es einen seltsamen String-Operator gibt, von dem ich nichts wusste

trotz
quelle

Antworten:

222

In .NET 4 können Sie dies tun:

String.Concat(Enumerable.Repeat("Hello", 4))
Will Dean
quelle
9
Und es ist nicht viel mehr in .NET 3.5: String.Concat (Enumerable.Repeat ("Hallo", 4) .ToArray ())
Mark Foreman
4
Ich finde es überhaupt nicht elegant. In Python lautet der Code dafür: snip * multiplier (Es ist nicht schrecklich ... aber es ist auch nicht schön).
wahnsinniger Igel
7
@dementedhedgehog Ich weiß, dass Sie Ihre eigene Demenz anerkennen, aber selbst wenn Sie leiden, können Sie möglicherweise feststellen, dass ein Python-Beispiel keine sehr gute Antwort auf eine C # -Frage gegeben hätte ... Ich denke, die meisten von uns können dies sehen Diese Sprachauswahl ist immer ein Kompromiss, und so ziemlich jede Antwort auf eine Frage könnte mit Befürwortung für oder gegen eine Fußnote versehen werden.
Will Dean
1
@will Dean: Ich habe mich nur auf Matthew Nichols Aussage über die Eleganz des Codes bezogen, den Sie dort haben. Soweit ich das beurteilen kann, ist Ihr Code für C #, wie er derzeit steht, für dieses Problem elegant. Der Punkt, den ich ansprechen möchte, ist: (Ich glaube) es wäre sehr einfach (für Microsoft, da Zeichenfolgen versiegelt sind), C # zu erweitern, um den Operator * zu überladen und eine int * Zeichenfolgenmultiplikation zu ermöglichen. Was dann tatsächlich in einem universellen Sinne elegant wäre, imho, nicht nur elegant im Kontext der Einschränkungen, die C # derzeit auferlegt.
wahnsinniger Igel
@dementedhedgehog Für mich widerspricht das, was Binär operator*darstellt. Für jeden das Richtige, denke ich.
TEK
99

Beachten Sie, dass, wenn Ihre "Zeichenfolge" nur ein einzelnes Zeichen ist, der Zeichenfolgenkonstruktor überlastet ist, um damit umzugehen:

int multipler = 10;
string TenAs = new string ('A', multipler);
James Curran
quelle
Das ist wirklich Pro.
Zaven Zareyan
61

Leider / zum Glück ist die String-Klasse versiegelt, sodass Sie nicht davon erben und den Operator * überladen können. Sie können jedoch eine Erweiterungsmethode erstellen:

public static string Multiply(this string source, int multiplier)
{
   StringBuilder sb = new StringBuilder(multiplier * source.Length);
   for (int i = 0; i < multiplier; i++)
   {
       sb.Append(source);
   }

   return sb.ToString();
}

string s = "</li></ul>".Multiply(10);
Tamas Czinege
quelle
5
Genau wohin ich ging! Sie könnten wahrscheinlich optimieren, indem Sie den Multiplikator source.Length * im StringBuilder ctor
Marc Gravell verwenden.
2
Marc's Kommentar war genau dort, wo ich hinging :)
Jon Skeet
1
Sie benötigen (source.Length * Multiplikator), nicht nur (Multiplikator)
Marc Gravell
1
Sehr sicher. Es ordnet einen String (dieser Länge) hinter den Kulissen zu und mutiert ihn dann. Es funktioniert nicht wie eine normale Liste <T> usw.
Marc Gravell
1
Die Verlängerungsmethode ist hier ideal.
Chris Ballance
12

Ich bin mit DrJokepu in diesem Fall , aber wenn Sie aus irgendeinem Grund mit der integrierten Funktionalität schummeln wollten, können Sie Folgendes tun:

string snip = "</li></ul>";
int multiplier = 2;

string result = string.Join(snip, new string[multiplier + 1]);

Oder wenn Sie .NET 4 verwenden:

string result = string.Concat(Enumerable.Repeat(snip, multiplier));

Persönlich würde ich mich aber nicht darum kümmern - eine benutzerdefinierte Erweiterungsmethode ist viel schöner.

LukeH
quelle
1
Ich wusste nie, dass es so einen Cheat gibt. =)
Jronny
10

Nur der Vollständigkeit halber - hier ist eine andere Möglichkeit, dies zu tun:

public static string Repeat(this string s, int count)
{
    var _s = new System.Text.StringBuilder().Insert(0, s, count).ToString();
    return _s;
}

Ich glaube, ich habe das vor einiger Zeit aus Stack Overflow gezogen, also ist es nicht meine Idee.

user51710
quelle
9

Sie müssten eine Methode schreiben - natürlich könnte es sich bei C # 3.0 um eine Erweiterungsmethode handeln:

public static string Repeat(this string, int count) {
    /* StringBuilder etc */ }

dann:

string bar = "abc";
string foo = bar.Repeat(2);
Marc Gravell
quelle
Hatte nicht einmal .NET3 Enumerable.Repeat?
Will Dean
@ Will - .NET 3 war WCF / WPF usw., also nein; es existiert zwar in .NET 3.5, aber dann müssten Sie string.Joines auch - warum nicht einfach n-mal schleifen? Viel direkter.
Marc Gravell
Danke - ich habe nicht richtig über 3.0 vs 3.5 nachgedacht. Warum nicht einfach eine Schleife verwenden, das ist sicherlich die ganze Essenz der funktionalen vs. imperativen Debatte? Ich habe eine .net 4-Antwort weiter unten gepostet, die meiner Meinung nach in der Debatte zwischen "funktionaler Klugheit" und "Schleifen-Offensichtlichkeit" nicht schlecht ist.
Will Dean
8

Ein wenig spät (und nur zum Spaß), wenn Sie den *Operator wirklich für diese Arbeit verwenden möchten , können Sie dies tun:

public class StringWrap
{
    private string value;
    public StringWrap(string v)
    {
        this.value = v;
    }
    public static string operator *(StringWrap s, int n)
    {
        return s.value.Multiply(n); // DrJokepu extension
    }
}

Und so:

var newStr = new StringWrap("TO_REPEAT") * 5;

Beachten Sie, dass, solange Sie in der Lage sind , ein vernünftiges Verhalten für sie zu finden, können Sie auch andere Betreiber durch handhaben StringWrapKlasse, wie \, ^, %etc ...

PS:

Multiply()Verlängerungsguthaben an @DrJokepu Alle Rechte vorbehalten ;-)

digEmAll
quelle
7

Das ist viel prägnanter:

new StringBuilder().Insert(0, "</li></ul>", count).ToString()

Der Namespace using System.Text;sollte in diesem Fall importiert werden.

user734119
quelle
2
string Multiply(string input, int times)
{
     StringBuilder sb = new StringBuilder(input.length * times);
     for (int i = 0; i < times; i++)
     {
          sb.Append(input);
     }
     return sb.ToString();
}
Chris Ballance
quelle
2

Wenn Sie .Net 3.5, aber nicht 4.0 haben, können Sie System.Linqs verwenden

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())
Frank Schwieterman
quelle
Um eine einzelne Zeichenfolge zu erhalten, benötigen Sie diese noch String.Concat, und auf 3.5 benötigen Sie sie auch .ToArray(). Ich fürchte, nicht die eleganteste Lösung.
Kobi
2

Da jeder seine eigenen .NET4 / Linq-Beispiele hinzufügt, kann ich auch meine eigenen hinzufügen. (Grundsätzlich ist es DrJokepus, reduziert auf einen Einzeiler)

public static string Multiply(this string source, int multiplier) 
{ 
    return Enumerable.Range(1,multiplier)
             .Aggregate(new StringBuilder(multiplier*source.Length), 
                   (sb, n)=>sb.Append(source))
             .ToString();
}
James Curran
quelle
0

Okay, hier ist meine Meinung zu diesem Thema:

public static class ExtensionMethods {
  public static string Multiply(this string text, int count)
  {
    return new string(Enumerable.Repeat(text, count)
      .SelectMany(s => s.ToCharArray()).ToArray());
  }
}

Ich bin natürlich ein bisschen albern, aber wenn ich Tabellen in Code-generierenden Klassen haben muss, erledigt Enumerable.Repeat das für mich. Und ja, die StringBuilder-Version ist auch in Ordnung.

Dmitri Nesteruk
quelle
0

Hier ist meine Meinung dazu nur zum späteren Nachschlagen:

    /// <summary>
    /// Repeats a System.String instance by the number of times specified;
    /// Each copy of thisString is separated by a separator
    /// </summary>
    /// <param name="thisString">
    /// The current string to be repeated
    /// </param>
    /// <param name="separator">
    /// Separator in between copies of thisString
    /// </param>
    /// <param name="repeatTimes">
    /// The number of times thisString is repeated</param>
    /// <returns>
    /// A repeated copy of thisString by repeatTimes times 
    /// and separated by the separator
    /// </returns>
    public static string Repeat(this string thisString, string separator, int repeatTimes) {
        return string.Join(separator, ParallelEnumerable.Repeat(thisString, repeatTimes));
    }
Jronny
quelle
Ich hoffe, Sie verwenden ParallelEnumerablein solchen Situationen nicht wirklich . string.Joinmuss die Elemente in der richtigen Reihenfolge verwenden, sodass eine Parallelisierung ihrer Generierung nicht erforderlich ist.
Gabe
@Gabe: Da die Artikel gleich sind und wirklich nur Kopien dieses Strings sind, muss ich mir hier wohl keine Sorgen um die Bestellung machen.
Jronny
Ich stimme vielen Lehrern auf diesem Gebiet zu, dass es normalerweise gut ist, zu codieren, um zu sagen, was Sie meinen. Es hat keinen Vorteil zu sagen, dass Sie diese Parallele wollen und nur insgeheim denken "Nun, ich weiß, dass es in diesem speziellen Fall sowieso nicht parallel sein wird"
sehe
Ich denke, es parallel zu machen macht es schneller, oder bitte klären Sie mich auf. Deshalb konvertiere ich dies in ParallelEnumerable, daher denke ich, dass ich Code schreibe, um zu sagen, was ich meine ... Danke.
Jronny