Apakah ada cara mudah untuk mengembalikan string berulang X kali?

318

Saya mencoba untuk memasukkan sejumlah lekukan sebelum string berdasarkan kedalaman item dan saya bertanya-tanya apakah ada cara untuk mengembalikan string yang diulang X kali. Contoh:

string indent = "---";
Console.WriteLine(indent.Repeat(0)); //would print nothing.
Console.WriteLine(indent.Repeat(1)); //would print "---".
Console.WriteLine(indent.Repeat(2)); //would print "------".
Console.WriteLine(indent.Repeat(3)); //would print "---------".
Abe Miessler
sumber
9
Tidak yakin apakah ini berlaku, tetapi Anda mungkin ingin melihat IndentedTextWriter juga.
Chris Shouts
Apakah Anda ingin mempertimbangkan untuk mengubah jawaban yang diterima karena pertanyaan Anda adalah tentang pengulangan string dan bukan karakter yang digambarkan oleh jawaban yang diterima? Mulai hari ini hingga .Net v4.7, setiap konstruktor Stringkelas yang kelebihan tidak mengambil string sebagai parameter untuk membuat pengulangan dari itu yang bisa membuat jawaban yang diterima cocok.
RBT

Jawaban:

538

Jika Anda hanya ingin mengulang karakter yang sama, Anda dapat menggunakan konstruktor string yang menerima karakter dan berapa kali mengulanginya new String(char c, int count).

Misalnya, untuk mengulangi tanda hubung lima kali:

string result = new String('-', 5);
Output: -----
Ahmad Mageed
sumber
8
Terima kasih telah mengingatkan saya tentang fitur kecil yang menyenangkan ini. Saya pikir itu hilang di sudut pikiran saya.
Chris Shouts
3
Karena tab metacharacter '\ t' adalah char, ini juga berfungsi untuk indentasi.
cori
91
Ini adalah trik C # yang sangat berguna, tetapi judul pertanyaannya adalah tentang string (bukan char). Jawaban lain di bawah ini sebenarnya menjawab pertanyaan, tetapi dinilai jauh lebih rendah. Saya tidak mencoba untuk tidak menghargai jawaban Ahmad, tetapi saya pikir salah satu judul pertanyaan ini harus diubah (jika pertanyaannya benar-benar mengenai karakter) atau jawaban yang lain benar-benar harus terangkat (dan bukan yang ini).
pghprogrammer4
14
@Ahmad Seperti yang saya katakan, saya tidak downvote karena saya pikir Anda tidak memberikan informasi yang baik, tetapi karena informasi yang Anda berikan tidak relevan untuk menjawab pertanyaan seperti yang dinyatakan saat ini . Bayangkan jika Anda sedang mencari cara untuk mengulangi string (bukan karakter) dan ketika Anda sampai pada pertanyaan yang relevan Anda harus menelusuri beberapa tips 'berguna' untuk mendapatkan jawaban aktual untuk pertanyaan itu. Jika downvote itu menyinggung Anda, saya bisa menghapusnya. Tapi apakah Anda melihat dari mana saya berasal? Apakah saya benar-benar tidak berada di sini?
pghprogrammer4
11
@ pghprogrammer4 IMHO, downvotes bisa sangat mengecewakan, dan seharusnya hanya digunakan untuk jawaban yang berbahaya / menyesatkan / benar-benar, yang membutuhkan perubahan besar atau harus dihapus oleh penulisnya. Jawaban ada karena orang bermurah hati dan ingin membagikan apa yang mereka ketahui. Secara umum, situs-situs ini benar-benar didorong oleh upvotes untuk membawa jawaban yang bermanfaat ke atas.
ToolmakerSteve
271

Jika Anda menggunakan .NET 4.0, Anda bisa menggunakannya string.Concatbersama Enumerable.Repeat.

int N = 5; // or whatever
Console.WriteLine(string.Concat(Enumerable.Repeat(indent, N)));

Kalau tidak, aku akan pergi dengan sesuatu seperti jawaban Adam .

Alasan saya umumnya tidak menyarankan menggunakan jawaban Andrey adalah karena ToArray()panggilan itu memperkenalkan overhead berlebihan yang dihindari dengan StringBuilderpendekatan yang disarankan oleh Adam. Yang mengatakan, setidaknya itu berfungsi tanpa memerlukan. NET 4.0; dan itu cepat dan mudah (dan tidak akan membunuh Anda jika efisiensi tidak terlalu menjadi perhatian).

Dan Tao
sumber
3
Ini akan bekerja dengan baik dengan string - seperti jika Anda perlu menggabungkan ruang tanpa putus (& nbsp;). Tapi saya berasumsi konstruktor string akan lebih cepat jika Anda berurusan dengan karakter ...
woodbase
1
Konstruktor string hanya akan berfungsi untuk satu karakter. untuk opsi menggunakan Concat Repeat akan bekerja untuk string
Eli Dagan
4
Terima kasih telah menjawab pertanyaan judul yang sebenarnya!
Mark K Cowan
Saya suka jawaban ini!
Ji_in_coding
Jika Anda mendapatkan -System.Linq.Enumerable dll sebagai output, itu karena Anda (ok, ini saya) terlalu cepat untuk menyalin / menempel dan memodifikasi cuplikan. Jika Anda perlu menggabungkan string yang berbeda ke output Enumerable. Ulangi, Anda perlu melakukannya seperti ini: Console.WriteLine(string.Concat("-", string.Concat(Enumerable.Repeat(indent, N))));
Gabe
47
public static class StringExtensions
{
    public static string Repeat(this string input, int count)
    {
        if (!string.IsNullOrEmpty(input))
        {
            StringBuilder builder = new StringBuilder(input.Length * count);

            for(int i = 0; i < count; i++) builder.Append(input);

            return builder.ToString();
        }

        return string.Empty;
    }
}
Adam Robinson
sumber
6
Mungkin juga lulus input.Length * countke StringBuilderkonstruktor, bukan begitu?
Dan Tao
Dan jika Anda meneruskan input.Length * countke StringBuilderkonstruktor, Anda dapat melewati StringBuildersemuanya dan membuat char [] dengan ukuran yang tepat segera.
dtb
@ dtb: Saya ingin tahu mengapa Anda ingin melakukan itu. Saya tidak bisa membayangkan bahwa itu akan jauh (jika ada) lebih cepat daripada menggunakan StringBuilder, dan kode akan kurang transparan.
Adam Robinson
@ dtb: yuck. Gunakan StringBuilder; itu dirancang untuk melakukan ini secara efisien.
ToolmakerSteve
Adam, saya melihat Anda pergi ke kesulitan menguji input untuk null ketika menambahkannya untuk menghitung, tetapi kemudian membiarkannya gagal, mengandalkan Append untuk tidak melakukan apa pun yang diberikan null. IMHO ini kurang jelas: jika nol adalah input yang mungkin, mengapa tidak menguji itu di depan, dan mengembalikan string kosong?
ToolmakerSteve
46

solusi paling performan untuk string

string result = new StringBuilder().Insert(0, "---", 5).ToString();
c0rd
sumber
1
Tentu adalah one-liner yang cantik. Tentu bukan yang paling performant. StringBuilder memiliki sedikit overhead dibandingkan jumlah concatenation yang sangat sedikit.
Teejay
25

Untuk banyak skenario, ini mungkin solusi yang paling rapi:

public static class StringExtensions
{
    public static string Repeat(this string s, int n)
        => new StringBuilder(s.Length * n).Insert(0, s, n).ToString();
}

Maka penggunaan adalah:

text = "Hello World! ".Repeat(5);

Ini didasarkan pada jawaban lain (khususnya @ c0rd). Serta kesederhanaan, ia memiliki fitur berikut, yang tidak semua teknik lain yang dibagikan berbagi:

  • Pengulangan string dengan panjang berapa pun, bukan hanya karakter (seperti yang diminta oleh OP).
  • Penggunaan yang efisien StringBuildermelalui preallokasi penyimpanan.
Bob Sammers
sumber
Saya setuju, ini luar biasa. Saya baru saja menambahkan ini ke kode saya dengan kredit ke Bob! Terima kasih!
John Burley
22

Gunakan String.PadLeft , jika string yang Anda inginkan hanya berisi satu karakter.

public static string Indent(int count, char pad)
{
    return String.Empty.PadLeft(count, pad);
}

Kredit jatuh tempo di sini

Steve Townsend
sumber
1
CIUMAN. Untuk apa kita membutuhkan StringBuilders dan ekstensi? Ini adalah masalah yang sangat sederhana.
DOK
1
Saya tidak tahu, ini sepertinya menyelesaikan masalah sebagaimana diungkapkan dengan keanggunan. Dan btw, siapa yang kamu panggil 'S'? :-)
Steve Townsend
7
Tapi bukankah ini benar-benar hanya versi yang kurang jelas dari para stringkonstruktor yang mengambil chardanint ?
Dan Tao
Ini akan terlihat lebih bagus dengan String.Empty daripada "" ... jika tidak, solusi yang baik;)
Thomas Levesque
@Steve BTW String.PadLeftargumen dibalik. Itu countdatang sebelum karakter padding.
Ahmad Mageed
17

Anda dapat mengulangi string Anda (kalau-kalau itu bukan char tunggal) dan menyetujui hasilnya, seperti ini:

String.Concat(Enumerable.Repeat("---", 5))
LiRoN
sumber
12

Saya akan mencari jawaban Dan Tao, tetapi jika Anda tidak menggunakan .NET 4.0 Anda dapat melakukan sesuatu seperti itu:

public static string Repeat(this string str, int count)
{
    return Enumerable.Repeat(str, count)
                     .Aggregate(
                        new StringBuilder(),
                        (sb, s) => sb.Append(s))
                     .ToString();
}
Thomas Levesque
sumber
3
Jika saya akan menemukan potongan ini di proyek saya, saya akan bertanya-tanya siapa yang telah melanggar KISS dan mengapa ... bagus kalau tidak
Noctis
4
        string indent = "---";
        string n = string.Concat(Enumerable.Repeat(indent, 1).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 2).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 3).ToArray());
Andrey
sumber
1
@ Adam: Saya kira Anda harus melakukan itu pra-. NET 4.0.
Dan Tao
3

Saya suka jawaban yang diberikan. Meskipun demikian, di sepanjang garis sames itulah yang saya gunakan di masa lalu:

"" .PadLeft (3 * Indent, '-')

Ini akan memenuhi pembuatan indentasi tetapi secara teknis pertanyaannya adalah mengulang sebuah string. Jika indentasi string adalah sesuatu seperti> - <maka ini juga jawaban yang diterima tidak akan berfungsi. Dalam hal ini solusi c0rd menggunakan stringbuilder terlihat bagus, meskipun overhead dari stringbuilder mungkin sebenarnya tidak membuatnya menjadi yang paling performant. Salah satu pilihan adalah membangun sebuah array string, mengisinya dengan string indentasi, lalu menyatukannya. Untuk sedikit pun:

int Indent = 2;

string[] sarray = new string[6];  //assuming max of 6 levels of indent, 0 based

for (int iter = 0; iter < 6; iter++)
{
    //using c0rd's stringbuilder concept, insert ABC as the indent characters to demonstrate any string can be used
    sarray[iter] = new StringBuilder().Insert(0, "ABC", iter).ToString();
}

Console.WriteLine(sarray[Indent] +"blah");  //now pretend to output some indented line

Kita semua menyukai solusi yang cerdas tetapi terkadang sederhana adalah yang terbaik.

Londo Mollari
sumber
3

Menambahkan Metode Ekstensi yang saya gunakan di seluruh proyek saya:

public static string Repeat(this string text, int count)
{
    if (!String.IsNullOrEmpty(text))
    {
        return String.Concat(Enumerable.Repeat(text, count));
    }
    return "";
}

Semoga seseorang dapat menggunakannya ...

Mayer Spitzer
sumber
2

Terkejut tidak ada yang pergi sekolah tua. Saya tidak membuat klaim apa pun tentang kode ini, tetapi hanya untuk bersenang-senang:

public static string Repeat(this string @this, int count)
{
    var dest = new char[@this.Length * count];
    for (int i = 0; i < dest.Length; i += 1)
    {
        dest[i] = @this[i % @this.Length];
    }
    return new string(dest);
}
OlduwanSteve
sumber
Jelas saya meninggalkan itu sebagai ujian bagi pembaca yang cerdik :) Sangat cerdik, terima kasih.
OlduwanSteve
1
Tidak ada yang kuno tentang penamaan parameter @ini, itu selalu merupakan ide yang mengerikan :)
Dave Jellison
2
Saya lebih suka tidak menggunakan kata kunci sebagai nama variabel kecuali dipaksa (seperti @class = "something" ketika bekerja dengan MVC karena Anda perlu kelas merujuk ke CSS tetapi itu kata kunci dalam C # (tentu saja). Ini bukan hanya saya yang berbicara, itu adalah aturan umum. Meskipun kode itu pasti dapat dikompilasi dan sah, pikirkan tentang kemudahan membaca dan mengetik juga, kedua alasan praktisnya. Saya sangat parsial menggunakan nama parameter untuk menggambarkan apa yang terjadi pertama kali jadi Ulangi (seed string ini, int hitungan) mungkin lebih ilho ilustratif
Dave Jellison
1
Menarik, terima kasih. Saya pikir dalam hal ini Anda mungkin benar bahwa @ ini kurang deskriptif dari yang seharusnya. Namun secara umum saya pikir itu cukup umum untuk memperluas kelas atau antarmuka di mana satu-satunya nama yang masuk akal untuk 'ini' agak generik. Jika Anda memiliki parameter yang disebut 'instance' atau 'it' atau 'str' (lihat MSDN ) maka yang mungkin Anda maksud adalah 'ini'.
OlduwanSteve
1
Saya pada dasarnya setuju dengan Anda, tetapi demi argumen ... karena saya tahu lebih banyak tentang string yang saya buat, saya bisa melakukan pekerjaan yang sedikit lebih baik daripada StringBuilder. StringBuilder harus membuat perkiraan ketika mengalokasikan memori. Memang itu tidak mungkin menjadi masalah dalam banyak skenario, tetapi seseorang di luar sana mungkin membangun sejumlah besar string berulang secara paralel dan senang untuk mendapatkan beberapa siklus clock kembali :)
OlduwanSteve
2

Tidak yakin bagaimana ini akan melakukan, tetapi itu adalah potongan kode yang mudah. (Saya mungkin membuatnya tampak lebih rumit daripada itu.)

int indentCount = 3;
string indent = "---";
string stringToBeIndented = "Blah";
// Need dummy char NOT in stringToBeIndented - vertical tab, anyone?
char dummy = '\v';
stringToBeIndented.PadLeft(stringToBeIndented.Length + indentCount, dummy).Replace(dummy.ToString(), indent);

Atau, jika Anda tahu jumlah level maksimum yang dapat Anda harapkan, Anda bisa mendeklarasikan array dan mengindeksnya. Anda mungkin ingin membuat array ini statis atau konstan.

string[] indents = new string[4] { "", indent, indent.Replace("-", "--"), indent.Replace("-", "---"), indent.Replace("-", "----") };
output = indents[indentCount] + stringToBeIndented;      
BH
sumber
2

Saya tidak punya cukup perwakilan untuk mengomentari jawaban Adam, tetapi cara terbaik untuk melakukannya adalah seperti ini:

public static string RepeatString(string content, int numTimes) {
        if(!string.IsNullOrEmpty(content) && numTimes > 0) {
            StringBuilder builder = new StringBuilder(content.Length * numTimes);

            for(int i = 0; i < numTimes; i++) builder.Append(content);

            return builder.ToString();
        }

        return string.Empty;
    }

Anda harus memeriksa untuk melihat apakah numTimes lebih besar dari nol, jika tidak, Anda akan mendapatkan pengecualian.

Gru
sumber
2

Saya tidak melihat solusi ini. Saya merasa lebih mudah untuk keberadaan saya saat ini dalam pengembangan perangkat lunak:

public static void PrintFigure(int shapeSize)
{
    string figure = "\\/";
    for (int loopTwo = 1; loopTwo <= shapeSize - 1; loopTwo++)
    {
        Console.Write($"{figure}");
    }
}
Nelly
sumber
2

Untuk penggunaan umum, solusi yang melibatkan kelas StringBuilder adalah yang terbaik untuk mengulang string multi-karakter. Ini dioptimalkan untuk menangani kombinasi sejumlah besar string dengan cara yang tidak dapat digabungkan dengan sederhana dan akan sulit atau tidak mungkin dilakukan secara lebih efisien dengan tangan. Solusi StringBuilder yang ditampilkan di sini menggunakan iterasi O (N) untuk menyelesaikan, laju rata yang proporsional dengan berapa kali itu diulang.

Namun, untuk jumlah pengulangan yang sangat besar, atau di mana tingkat efisiensi yang tinggi harus ditekan, pendekatan yang lebih baik adalah melakukan sesuatu yang mirip dengan fungsi dasar StringBuilder tetapi untuk menghasilkan salinan tambahan dari tujuan, daripada dari string asli, seperti di bawah ini.

    public static string Repeat_CharArray_LogN(this string str, int times)
    {
        int limit = (int)Math.Log(times, 2);
        char[] buffer = new char[str.Length * times];
        int width = str.Length;
        Array.Copy(str.ToCharArray(), buffer, width);

        for (int index = 0; index < limit; index++)
        {
            Array.Copy(buffer, 0, buffer, width, width);
            width *= 2;
        }
        Array.Copy(buffer, 0, buffer, width, str.Length * times - width);

        return new string(buffer);
    }

Ini menggandakan panjang string sumber / tujuan dengan setiap iterasi, yang menghemat overhead pengaturan ulang penghitung setiap kali akan melewati string asli, alih-alih membaca dengan lancar dan menyalin string yang sekarang jauh lebih lama, sesuatu yang prosesor modern dapat lakukan banyak lebih efisien.

Ia menggunakan basis-2 logaritma untuk menemukan berapa kali perlu menggandakan panjang string dan kemudian mulai melakukannya berkali-kali. Karena sisa yang akan disalin sekarang kurang dari total panjangnya menyalin, maka kemudian hanya dapat menyalin subset dari apa yang telah dihasilkan.

Saya telah menggunakan metode Array.Copy () atas penggunaan StringBuilder, karena menyalin isi dari StringBuilder ke dalam dirinya sendiri akan memiliki overhead menghasilkan string baru dengan konten itu dengan setiap iterasi. Array.Copy () menghindari ini, sambil tetap beroperasi dengan tingkat efisiensi yang sangat tinggi.

Solusi ini mengambil iterasi O (1 + log N) untuk menyelesaikan, tingkat yang meningkat secara logaritmik dengan jumlah pengulangan (menggandakan jumlah pengulangan sama dengan satu iterasi tambahan), penghematan yang substansial dibandingkan metode lain, yang meningkat secara proporsional.

buchWyrm
sumber
1

Pendekatan lain adalah untuk mempertimbangkan stringsebagai IEnumerable<char>dan memiliki metode ekstensi generik yang akan memperbanyak item dalam koleksi dengan faktor tertentu.

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}

Jadi dalam kasus Anda:

string indent = "---";
var f = string.Concat(indent.Repeat(0)); //.NET 4 required
//or
var g = new string(indent.Repeat(5).ToArray());
nawfal
sumber
1

Cetak garis dengan pengulangan.

Console.Write(new string('=', 30) + "\n");

==============================

Kamal
sumber
Mengapa Anda tidak menggunakan Console.WriteLine alih-alih menambahkan \ n di akhir string?
InxaneNinja
-1

Anda dapat membuat ExtensionMethod untuk melakukannya!

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    string ret = "";

    for (var x = 0; x < count; x++)
    {
      ret += str;
    }

    return ret;
  }
}

Atau menggunakan solusi @Dan Tao:

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    if (count == 0)
      return "";

    return string.Concat(Enumerable.Repeat(indent, N))
  }
}
Zote
sumber
3
Lihat komentar saya untuk jawaban Kyle
Thomas Levesque