¿Puedo "multiplicar" una cadena (en C #)?

136

Supongamos que tengo una cadena, por ejemplo,

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

Básicamente, quiero escribirlo varias veces, dependiendo de algún valor entero.

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

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

EDITAR: Sé que puedo escribir fácilmente mi propia función para implementar esto, me preguntaba si había algún operador de cadena extraño que no conociera

A pesar de
fuente

Respuestas:

222

En .NET 4 puedes hacer esto:

String.Concat(Enumerable.Repeat("Hello", 4))
Will Dean
fuente
9
Y no es mucho más en .NET 3.5: String.Concat (Enumerable.Repeat ("Hello", 4) .ToArray ())
Mark Foreman
44
No creo que sea elegante en absoluto. En python, el código para hacer esto es: snip * multiplicador (no es horrible ... pero tampoco es hermoso).
erizo demente
77
@dementedhedgehog Sé que reconoces tu propia demencia, pero incluso sufriendo mientras lo haces, podrías ver que un ejemplo de Python no habría sido una muy buena respuesta a una pregunta de C # ... Creo que la mayoría de nosotros podemos ver esa selección de idioma siempre es un compromiso, y casi cualquier respuesta a cualquier pregunta podría ser puesta al pie de página con incidencia, ya sea a favor o en contra.
Will Dean
1
@will decano: me refería a la declaración de Matthew Nichols sobre la elegancia del código que tienes allí. Por lo que puedo decir, su código es elegante para C #, tal como está actualmente, para este problema. El punto que estoy tratando de hacer es: (creo) que sería muy fácil (para microsoft, ya que las cadenas están selladas) extender C # para sobrecargar el operador * para permitir la multiplicación de cadenas int *. Lo que en realidad sería elegante en algún sentido universal, en mi opinión, no solo elegante dentro del contexto de las restricciones impuestas por C # tal como existe en este momento.
erizo demente
@dementedhedgehog Para mí, eso va en contra de lo que operator*representa el binario . A cada uno lo suyo, supongo.
TEK
99

Tenga en cuenta que si su "cadena" es solo un carácter, hay una sobrecarga del constructor de cadenas para manejarlo:

int multipler = 10;
string TenAs = new string ('A', multipler);
James Curran
fuente
Esto es realmente profesional.
Zaven Zareyan
61

Desafortunadamente / afortunadamente, la clase de cadena está sellada, por lo que no puede heredarla y sobrecargar el operador *. Sin embargo, puede crear un método de extensión:

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
fuente
55
Justo a donde iba! Probablemente podría optimizar utilizando source.Length * multiplicador en el ctor StringBuilder
Marc Gravell
2
El comentario de Marc fue justo donde yo iba :)
Jon Skeet
1
Necesitas (fuente, longitud * multiplicador), no solo (multiplicador)
Marc Gravell
1
Muy seguro. Asigna una cadena (de esa longitud) detrás de escena, luego la muta. No funciona como una lista normal <T> etc.
Marc Gravell
1
El método de extensión es ideal aquí.
Chris Ballance
12

Estoy con DrJokepu en este caso , pero si por alguna razón quisiste hacer trampa usando la funcionalidad incorporada, entonces podrías hacer algo como esto:

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

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

O, si está utilizando .NET 4:

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

Sin embargo, personalmente no me molestaría: un método de extensión personalizado es mucho mejor.

LukeH
fuente
1
Nunca supe que había un truco como este. =)
Jronny
10

Solo por completo, aquí hay otra forma de hacer esto:

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

Creo que lo saqué de Stack Overflow hace algún tiempo, así que no es mi idea.

usuario51710
fuente
9

Tendría que escribir un método; por supuesto, con C # 3.0 podría ser un método de extensión:

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

luego:

string bar = "abc";
string foo = bar.Repeat(2);
Marc Gravell
fuente
¿Ni siquiera .NET3 tenía Enumerable.Repeat?
Will Dean
@Will - .NET 3 era WCF / WPF, etc., así que no; existe en .NET 3.5, pero entonces también lo necesitarías string.Join, ¿por qué no simplemente recorrer n veces? Mucho más directo.
Marc Gravell
Gracias, no estaba pensando correctamente en 3.0 vs 3.5. ¿Por qué no solo usar un bucle, seguramente esa es toda la esencia del debate funcional vs imperativo? Publiqué una respuesta .net 4 más abajo, que creo que no es tan mala en el debate de 'inteligencia funcional' versus 'evidencia de bucle'.
Will Dean
8

Un poco tarde (y solo por diversión), si realmente desea utilizar el *operador para este trabajo, puede hacer esto:

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

Y entonces:

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

Tenga en cuenta que, siempre y cuando usted es capaz de encontrar un comportamiento razonable para ellos, también puede manejar otros operadores a través de StringWrapla clase, como \, ^, %etc ...

PD:

Multiply()créditos de extensión a @DrJokepu todos los derechos reservados ;-)

digEmAll
fuente
7

Esto es mucho más conciso:

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

El espacio de nombres using System.Text;debe importarse en este caso.

usuario734119
fuente
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
fuente
2

Si tiene .Net 3.5 pero no 4.0, puede usar System.Linq's

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())
Frank Schwieterman
fuente
Para obtener una sola cadena que aún necesitarías String.Concat, y en 3.5 también necesitarías .ToArray(). No es la solución más elegante, me temo.
Kobi
2

Como todos están agregando sus propios ejemplos .NET4 / Linq, también podría agregar el mío. (Básicamente, es DrJokepu, reducido a una frase)

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
fuente
0

Bien, aquí está mi opinión sobre el asunto:

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

Estoy siendo un poco tonto, por supuesto, pero cuando necesito tener tabulación en clases generadoras de código, Enumerable.Repeat lo hace por mí. Y sí, la versión StringBuilder también está bien.

Dmitri Nesteruk
fuente
0

Aquí está mi opinión sobre esto solo para referencia futura:

    /// <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
fuente
Espero que realmente no lo uses ParallelEnumerableen situaciones como esta. string.Joinnecesita usar los elementos en orden, por lo que no es necesario paralelizar su generación.
Gabe
@Gabe: Dado que los artículos son los mismos y en realidad son solo copias de thisString, supongo que no hay que preocuparse por el pedido aquí.
Jronny
Estoy de acuerdo con muchos maestros en el campo que generalmente es bueno codificar para decir lo que quieres decir. No hay ningún beneficio en decir que quieres este paralelo y solo piensas en secreto "Bueno, sé que de todos modos no será paralelo en este caso en particular"
Sehe
Creo que hacerlo en paralelo lo hace más rápido, o por favor, ilumíneme. Es por eso que estoy convirtiendo esto a ParallelEnumerable, por lo que creo que codifico para decir lo que quiero decir ... Gracias.
Jronny