Posso "multiplicar" uma string (em C #)?


136

Suponha que eu tenha uma string, por exemplo,

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

Quero basicamente escrever várias vezes, dependendo de algum valor inteiro.

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

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

Edição: Eu sei que posso facilmente escrever minha própria função para implementar isso, eu só estava me perguntando se havia algum operador de string estranho que eu não sabia sobre


Respostas:


222

No .NET 4, você pode fazer isso:

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

9
E não é muito mais em .NET 3.5: String.Concat (Enumerable.Repeat ( "Olá", 4) .ToArray ())
Mark Foreman

4
Eu não acho nada elegante. Em python, o código para fazer isso é: snip * multiplicador (não é horrível .. mas também não é bonito).
ouriço demente Dem

7
@dementedhedgehog Eu sei que você reconhece sua própria demência, mas mesmo sofrendo, você pode ver que um exemplo em Python não teria sido uma resposta muito boa para uma pergunta em C # ... Eu acho que a maioria de nós pode ver que a seleção de idiomas é sempre um compromisso, e praticamente qualquer resposta a qualquer pergunta pode ser mencionada na advocacia, a favor ou contra.
Will Dean

1
@ Dean Dean: Acabei de me referir à declaração de Matthew Nichols sobre a elegância do código que você tem lá. Tanto quanto posso dizer, seu código é elegante para C #, como está atualmente, para esse problema. O ponto que estou tentando enfatizar é: (acredito) seria muito fácil (para a Microsoft, como as strings são seladas) estender o C # para sobrecarregar o operador * para permitir a multiplicação int * da string. O que seria realmente elegante em algum sentido universal, não apenas elegante dentro do contexto das restrições impostas pelo C #, como existe no momento.
ouriço demente Dem

@dementedhedgehog Para mim, isso vai contra o que o binário operator*representa. Para cada um deles, eu acho.
TEK 15/01

99

Observe que se sua "string" é apenas um caractere, há uma sobrecarga do construtor de string para lidar com isso:

int multipler = 10;
string TenAs = new string ('A', multipler);

Isso é realmente profissional.
Zaven Zareyan 29/11/19

61

Infelizmente / felizmente, a classe string é selada para que você não possa herdar dela e sobrecarregar o operador *. Você pode criar um método de extensão:

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

5
Apenas para onde eu estava indo! Você provavelmente poderia otimizar usando o multiplicador source.Length * no ctor StringBuilder
Marc Gravell

2
O comentário de Marc foi exatamente onde eu estava indo :)
Jon Skeet

1
Você precisa (source.Length * multiplicador), não apenas (multiplicador)
Marc Gravell

1
Muita certeza. Ele aloca uma string (desse comprimento) nos bastidores e depois a modifica. Não funciona como uma lista normal <T> etc.
Marc Gravell

1
O método de extensão é ideal aqui.
22710 Chris Ballance

12

Estou com o DrJokepu , mas se, por algum motivo, você quiser trapacear usando a funcionalidade incorporada, poderá fazer algo assim:

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

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

Ou, se você estiver usando o .NET 4:

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

Pessoalmente, eu não me incomodaria - um método de extensão personalizado é muito melhor.


1
Eu nunca soube que havia uma trapaça como esta. =)
Jronny 21/07

10

Apenas por uma questão de integridade - aqui está outra maneira de fazer isso:

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

Acho que peguei esse no Stack Overflow há algum tempo, então não é minha ideia.


9

Você precisaria escrever um método - é claro, com o C # 3.0, poderia ser um método de extensão:

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

então:

string bar = "abc";
string foo = bar.Repeat(2);

Nem o .NET3 tinha Enumerable.Repeat?
Will Dean

@ Will - .NET 3 foi WCF / WPF etc, então não; ele existe no .NET 3.5, mas você precisaria string.Jointambém - por que não apenas repetir n vezes? Muito mais direto.
Marc Gravell

Obrigado - eu não estava pensando corretamente sobre 3.0 vs 3.5. Por que não usar apenas um loop, certamente essa é toda a essência do debate funcional versus imperativo? Eu publiquei uma resposta .net 4 abaixo, que eu acho que não é tão ruim no debate 'esperteza funcional' vs 'óbvio em loop'.
Will Dean

8

Um pouco tarde (e apenas por diversão), se você realmente quiser usar o *operador para este trabalho, poderá fazer o seguinte:

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

E entao:

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

Note-se que, desde que você é capaz de encontrar um comportamento razoável para eles, você também pode lidar com outros operadores através de StringWrapclasse, como \, ^, %etc ...

PS:

Multiply()créditos de extensão para @DrJokepu todos os direitos reservados ;-)


7

Isso é muito mais conciso:

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

O espaço using System.Text;para nome deve ser importado nesse 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

Se você possui .Net 3.5, mas não 4.0, pode usar o System.Linq

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

Para obter uma única string que você ainda precisa String.Concat, e na versão 3.5 também .ToArray(). Receio que não seja a solução mais elegante.
Kobi

2

Como todo mundo está adicionando seus próprios exemplos do .NET4 / Linq, é melhor adicionar os meus. (Basicamente, DrJokepu's, reduzido a uma linha)

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

Ok, aqui está minha opinião sobre o assunto:

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

Estou sendo um pouco bobo, é claro, mas quando preciso ter tabulação nas classes geradoras de código, o Enumerable.Repeat faz isso por mim. E sim, a versão StringBuilder também está bem.


0

Aqui está minha opinião sobre isso apenas para referência 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 você realmente não use ParallelEnumerableem situações como esta. string.Joinprecisa usar os elementos em ordem; portanto, paralelizar sua geração é desnecessário.
Gabe

@ Gabe: Como os itens são os mesmos e são realmente apenas cópias desta string, não há necessidade de se preocupar com o pedido aqui, eu acho.
Jronny

Eu concordo com muitos professores da área que geralmente é bom codificar para dizer o que você quer dizer. Não há nenhum benefício para dizer que você quer esse paralelo e só secretamente pensar "Bem, eu sei que não vai ser paralelo, neste caso particular de qualquer maneira"
sehe

Eu acho que torná-lo paralelo torna mais rápido, ou por favor, me esclareça. É por isso que estou convertendo isso para ParallelEnumerable, portanto, acho que codifico para dizer o que quero dizer ... Obrigado.
Jronny
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.