Bisakah saya "mengalikan" string (di C #)?

136

Misalkan saya memiliki string, misalnya,

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

Saya pada dasarnya ingin menulisnya beberapa kali, tergantung pada beberapa nilai integer.

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

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

EDIT: Saya tahu saya dapat dengan mudah menulis fungsi saya sendiri untuk mengimplementasikan ini, saya hanya ingin tahu apakah ada operator string aneh yang tidak saya ketahui

meskipun
sumber

Jawaban:

224

Di .NET 4 Anda dapat melakukan ini:

String.Concat(Enumerable.Repeat("Hello", 4))
Will Dean
sumber
9
Dan tidak lebih di .NET 3.5: String.Concat (Enumerable.Repeat ("Hello", 4) .ToArray ())
Mark Foreman
4
Saya tidak berpikir itu elegan sama sekali. Dalam python kode untuk melakukan ini adalah: snip * multiplier (Ini tidak mengerikan .. tapi juga tidak indah).
landak gila pada
7
@dementedhedgehog Saya tahu Anda mengakui demensia Anda sendiri, tetapi meski menderita seperti yang Anda alami, Anda mungkin dapat melihat bahwa contoh Python tidak akan memberikan jawaban yang sangat baik untuk pertanyaan C # ... Saya rasa sebagian besar dari kita dapat melihat bahwa pemilihan bahasa selalu merupakan kompromi, dan hampir semua jawaban atas pertanyaan apa pun dapat dicatat dengan dukungan, baik mendukung atau menentang.
Akankah Dean
1
@ Will Dean: Saya baru saja merujuk pada pernyataan Matthew Nichols tentang keanggunan kode yang Anda miliki di sana. Sejauh yang saya tahu kode Anda elegan untuk C #, seperti saat ini berdiri, untuk masalah ini. Poin yang saya coba buat adalah: (Saya percaya) akan sangat mudah (untuk microsoft, karena string disegel) untuk memperpanjang C # untuk membebani operator * untuk memungkinkan perkalian int * string. Yang kemudian akan benar-benar elegan dalam arti universal, imho, tidak hanya elegan dalam konteks batasan yang dipaksakan oleh C # seperti yang ada saat ini.
landak gila
1
@dementedhedgehog Bagi saya, itu bertentangan dengan apa yang operator*diwakili oleh biner . Untuk masing-masing milik mereka, kurasa.
TEK
100

Perhatikan bahwa jika "string" Anda hanya satu karakter, ada kelebihan konstruktor string untuk menanganinya:

int multipler = 10;
string TenAs = new string ('A', multipler);
James Curran
sumber
Ini benar-benar pro.
Zaven Zareyan
61

Sayangnya / untungnya, kelas string disegel sehingga Anda tidak dapat mewarisinya dan membebani operator *. Anda dapat membuat metode ekstensi:

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
sumber
5
Kemana aku pergi! Anda mungkin bisa mengoptimalkan dengan menggunakan pengali source.Length * di ctor StringBuilder
Marc Gravell
2
Komentar Marc tepat di mana saya pergi :)
Jon Skeet
1
Anda membutuhkan (source.Length * multiplier), bukan hanya (multiplier)
Marc Gravell
1
Sangat yakin. Ini mengalokasikan string (dengan panjang itu) di belakang layar, lalu memutasinya. Ini tidak bekerja seperti List <T> biasa dll.
Marc Gravell
1
Metode penyuluhan sangat ideal di sini.
Chris Ballance
12

Saya bersama DrJokepu dalam hal ini , tetapi jika karena alasan tertentu Anda memang ingin menipu menggunakan fungsionalitas bawaan maka Anda dapat melakukan sesuatu seperti ini:

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

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

Atau, jika Anda menggunakan .NET 4:

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

Secara pribadi saya tidak akan repot-repot - metode ekstensi khusus jauh lebih baik.

LukeH
sumber
1
Saya tidak pernah tahu ada cheat seperti ini. =)
Jronny
10

Hanya demi kelengkapan - berikut adalah cara lain untuk melakukan ini:

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

Saya rasa saya menariknya dari Stack Overflow beberapa waktu lalu, jadi itu bukan ide saya.

pengguna51710
sumber
9

Anda harus menulis metode - tentu saja, dengan C # 3.0 ini bisa menjadi metode ekstensi:

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

kemudian:

string bar = "abc";
string foo = bar.Repeat(2);
Marc Gravell
sumber
Bahkan .NET3 tidak memiliki Enumerable.Repeat?
Akankah Dean
@Will - .NET 3 adalah WCF / WPF dll, jadi tidak; itu memang ada di .NET 3.5, tetapi Anda juga membutuhkannya string.Join- mengapa tidak mengulang n kali? Jauh lebih langsung.
Marc Gravell
Terima kasih - Saya tidak berpikir dengan benar tentang 3.0 vs 3.5. Tentang mengapa tidak menggunakan loop saja, pasti itulah inti dari perdebatan fungsional vs imperatif? Saya memposting jawaban .net 4 lebih rendah yang menurut saya tidak terlalu buruk dalam perdebatan 'kepintaran fungsional' vs 'kejelasan perulangan'.
Akankah Dean
8

Agak terlambat (dan hanya untuk iseng), jika Anda benar-benar ingin menggunakan *operator untuk pekerjaan ini, Anda dapat melakukan ini:

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

Sehingga:

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

Perhatikan bahwa, selama Anda dapat menemukan perilaku yang wajar bagi mereka, Anda juga dapat menangani operator lain melalui StringWrapkelas, seperti \, ^, %dll ...

PS:

Multiply()kredit ekstensi ke @DrJokepu semua hak dilindungi ;-)

digEmAll
sumber
8

Ini jauh lebih ringkas:

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

Namespace using System.Text;harus diimpor dalam kasus ini.

pengguna734119
sumber
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
sumber
2

Jika Anda memiliki .Net 3.5 tetapi tidak 4.0, Anda dapat menggunakan System.Linq's

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())
Frank Schwieterman
sumber
Untuk mendapatkan satu senar Anda masih perlu String.Concat, dan pada 3.5 Anda juga perlu .ToArray(). Bukan solusi yang paling elegan, saya khawatir.
Kobi
2

Karena setiap orang menambahkan contoh .NET4 / Linq mereka sendiri, saya mungkin juga menambahkan contoh saya sendiri. (Pada dasarnya, ini milik DrJokepu, direduksi menjadi satu baris)

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

Oke, ini pendapat saya tentang masalah ini:

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

Tentu saja saya agak konyol, tetapi ketika saya perlu memiliki tabulasi di kelas penghasil kode, Enumerable. Ulangi melakukannya untuk saya. Dan ya, versi StringBuilder juga baik-baik saja.

Dmitri Nesteruk
sumber
0

Inilah pendapat saya tentang ini hanya untuk referensi di masa mendatang:

    /// <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
sumber
Saya harap Anda tidak benar-benar menggunakannya ParallelEnumerabledalam situasi seperti ini. string.Joinperlu menggunakan elemen secara berurutan, jadi memparalelkan pembuatannya tidak beralasan.
Gabe
@Gabe: Karena itemnya sama dan sebenarnya hanya salinan dari string ini, saya rasa tidak perlu khawatir tentang pemesanan di sini.
Jronny
Saya setuju dengan banyak guru di lapangan bahwa biasanya baik untuk membuat kode untuk mengatakan apa yang Anda maksud. Tidak ada untungnya mengatakan Anda menginginkan paralel ini dan hanya diam-diam berpikir "Yah, saya tahu ini tidak akan paralel dalam kasus khusus ini"
lihat
Saya pikir membuatnya paralel membuatnya lebih cepat, atau tolong beri saya pencerahan. Itu sebabnya saya mengubah ini menjadi ParallelEnumerable, jadi saya pikir saya membuat kode untuk mengatakan apa yang saya maksud ... Terima kasih.
Jronny