¿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


Respuestas:


222

En .NET 4 puedes hacer esto:

String.Concat(Enumerable.Repeat("Hello", 4))

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

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

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.


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.


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

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


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.


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

2

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

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())

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

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.


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

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.