วิธีที่ดีที่สุดในการทำซ้ำตัวละครใน C #


814

นี่เป็นวิธีที่ดีที่สุดในการสร้างสตริงของ\tใน C #

ฉันกำลังเรียนรู้ C # และทดลองใช้วิธีต่าง ๆ ในการพูดสิ่งเดียวกัน

Tabs(uint t)เป็นฟังก์ชั่นที่ส่งกลับstringกับtปริมาณของ\t's

ตัวอย่างเช่นTabs(3)ผลตอบแทน"\t\t\t"

วิธีการดำเนินการสามแบบTabs(uint numTabs)ใดที่ดีที่สุด

แน่นอนขึ้นอยู่กับความหมายของ "ดีที่สุด"

  1. เวอร์ชัน LINQ เป็นเพียงสองบรรทัดซึ่งดีมาก แต่การเรียกซ้ำและการรวมใช้เวลา / ทรัพยากรโดยไม่จำเป็น

  2. StringBuilderรุ่นมีความชัดเจนมาก แต่เป็นStringBuilderระดับใดช้าลง?

  3. stringรุ่นพื้นฐานซึ่งหมายความว่ามันเป็นเรื่องง่ายที่จะเข้าใจ

  4. มันไม่สำคัญเลยเหรอ? พวกเขาเท่ากันทั้งหมดหรือไม่

นี่คือคำถามทั้งหมดที่ช่วยให้ฉันรู้สึกดีขึ้นสำหรับ C #

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat("\t", (int) numTabs);
    return (numTabs > 0) ? tabs.Aggregate((sum, next) => sum + next) : ""; 
}  

private string Tabs(uint numTabs)
{
    StringBuilder sb = new StringBuilder();
    for (uint i = 0; i < numTabs; i++)
        sb.Append("\t");

    return sb.ToString();
}  

private string Tabs(uint numTabs)
{
    string output = "";
    for (uint i = 0; i < numTabs; i++)
    {
        output += '\t';
    }
    return output; 
}

คำตอบ:


1491

เกี่ยวกับสิ่งนี้:

string tabs = new String('\t', n);

ที่ไหนnคือจำนวนครั้งที่คุณต้องการที่จะทำซ้ำสตริง

หรือดีกว่า:

static string Tabs(int n)
{
    return new String('\t', n);
}

2
มีวิธีที่จะทำซ้ำคำนี้หรือไม่? แทนการใช้ '\ t' วิธีใช้ "เวลา"
asdfkjasdfjk

6
@ user1478137 หรือดีกว่า (ลงไปอีก): นี่
Xynariz

161
string.Concat(Enumerable.Repeat("ab", 2));

ผลตอบแทน

"Abab"

และ

string.Concat(Enumerable.Repeat("a", 2));

ผลตอบแทน

"AA"

จาก...

มีฟังก์ชันในตัวเพื่อทำซ้ำสตริงหรืออักขระใน. net


1
ทำให้ดีขึ้นโดยการทำโดยไม่ต้อง Linq และด้วยStruingBuilder!
Bitterblue

4
'' StringBuilder '' ไม่จำเป็นต้องเร็วกว่าstackoverflow.com/questions/585860/ …
Schiavini

6
อาจไม่เร็วกว่านี้ แต่สามารถบันทึกการจัดสรรหน่วยความจำ (ความดัน) ได้หากคุณระบุความจุที่ถูกต้องไว้ด้านหน้าและนั่นอาจเป็นสิ่งที่สำคัญพอ ๆ
wekempf

1
var strRepeat = string.Concat (Enumerable.Repeat ("ABC", 1000000)); // 50ms
yongfa365

1
@Phap string.Joinเป็นตัวอย่างที่เร็วกว่าเนื่องจากใช้ตัวคั่นช่องว่าง string.Concatเหมาะสมเมื่อไม่มีตัวคั่น
คาร์เตอร์ Medlin

124

ใน. NET ทุกรุ่นคุณสามารถทำซ้ำสตริงได้ดังนี้

public static string Repeat(string value, int count)
{
    return new StringBuilder(value.Length * count).Insert(0, value, count).ToString();
}

ในการเล่นซ้ำตัวละครnew String('\t', count)เป็นทางออกที่ดีที่สุด ดูคำตอบโดย @CMS


7
นี่คือประสิทธิภาพที่เร็วที่สุดที่ชาญฉลาดสำหรับ String วิธีอื่นสร้างค่าใช้จ่ายมากเกินไป
midspace

@midspace คุณรู้หรือไม่ถ้ามีใครอธิบายว่าทำไมคำตอบอื่น ๆ ถึงแย่ลง? ฉันจะสันนิษฐานว่าสตริงพื้นเมือง Concat จะได้รับการปรับให้เหมาะกับภายในเช่นเดียวกับ StringBuilder
Marie

@Marie บทความต่อไปนี้จะอธิบายถึงข้อดีบางประการ support.microsoft.com/en-au/help/306822/…มิฉะนั้นปัจจัยสองประการคือ StringBuilder อนุญาตให้ใช้สตริงและไม่ จำกัด เพียงตัวอักษร (แม้ว่าจะไม่เกี่ยวข้องกับคำถามดั้งเดิม) และสตริง คำตอบ Concat ด้านบนต้องสร้างอาร์เรย์ขึ้นมาก่อนโดยใช้ Enumerable ทำซ้ำ อย่างที่ฉันบอกไปมันเป็นค่าใช้จ่ายที่ไม่จำเป็น
midspace

ฉันคิดว่ามันจะไม่สร้างอาร์เรย์ขึ้นมาก่อนเพราะมันสามารถวนซ้ำไอเท็มได้ ขอบคุณสำหรับลิงค์ฉันจะอ่านมัน!
มารี

63

รุ่นที่ดีที่สุดคือการใช้วิธีการ builtin:

string Tabs(int len) { return new string('\t', len); }

จากโซลูชันอื่น ๆ ต้องการวิธีที่ง่ายที่สุด; หากสิ่งนี้พิสูจน์ได้ช้าเกินไปให้พยายามแก้ปัญหาที่มีประสิทธิภาพมากขึ้น

หากคุณใช้ a StringBuilderและทราบระยะเวลาที่ได้รับล่วงหน้าแล้วให้ใช้ตัวสร้างที่เหมาะสมซึ่งจะมีประสิทธิภาพมากกว่าเนื่องจากหมายความว่ามีการจัดสรรที่ใช้เวลานานเพียงครั้งเดียวและไม่มีการคัดลอกข้อมูลที่ไม่จำเป็น ไร้สาระ: แน่นอนรหัสข้างต้นมีประสิทธิภาพมากขึ้น


12
sb.Append ('\ t', len);
dan-gph

7
การวัดประสิทธิภาพของฉันกำลังแสดงnew string('\t', len)อยู่ระหว่าง 2x และ 7x เร็วกว่าStringBuilderวิธีการ เหตุใดคุณคิดว่าStringBuilderมีประสิทธิภาพมากกว่าในกรณีนี้
StriplingWarrior

6
@StriplingWarrior ขอบคุณสำหรับการแก้ไขนี้ (หลังจากที่ได้รับการยืนอยู่ที่นี่เป็นเวลาสองปีไม่น้อย!)
Konrad Rudolph

51

วิธีการขยาย:

public static string Repeat(this string s, int n)
{
    return new String(Enumerable.Range(0, n).SelectMany(x => s).ToArray());
}

public static string Repeat(this char c, int n)
{
    return new String(c, n);
}

39
กาลครั้งหนึ่งนานมาแล้วที่ผู้คนใช้ลูป
prabhakaran

2
@prabhakaran ฉันเห็นด้วย แต่ข้อดีของ Linq คือการสื่อสาร; แทบจะเป็นเรื่องไม่สมควรที่จะนำนิพจน์ Linq ไปใช้อีกครั้งโดยใช้โครงสร้างที่จำเป็น
Rodrick Chapman

10
Enumerable.Range(0, n).SelectMany(x => s)Enumerable.Repeat(s, n)จะถูกแทนที่ด้วยง่าย
Palec

5
@Palec ไม่มันไม่สามารถทำได้ SelectManyประสงค์สำหรับแต่ละหุ่นเดียวxให้ลำดับของcharค่า (ตั้งแต่string sการดำเนินการIEnumerable<char>) และบรรดาcharลำดับจะถูกตัดแบ่งยาวหนึ่งcharลำดับ IEnumerable<string>สิ่งที่คุณแนะนำแทนจะให้ มันไม่เหมือนกัน
Jeppe Stig Nielsen

2
ฉันผิด @JeppeStigNielsen ขอบคุณสำหรับหัวขึ้น. ถ้าฉันต้องการใช้จริงๆEnumerable.Repeatฉันจะต้องต่อสายเข้าด้วยกัน: string.Concat(Enumerable.Repeat(s, n)). นี้ได้รับการโพสต์ก่อน
Palec

40

แล้ววิธีการใช้นามสกุล


public static class StringExtensions
{
   public static string Repeat(this char chatToRepeat, int repeat) {

       return new string(chatToRepeat,repeat);
   }
   public  static string Repeat(this string stringToRepeat,int repeat)
   {
       var builder = new StringBuilder(repeat*stringToRepeat.Length);
       for (int i = 0; i < repeat; i++) {
           builder.Append(stringToRepeat);
       }
       return builder.ToString();
   }
}

จากนั้นคุณสามารถเขียน:

Debug.WriteLine('-'.Repeat(100)); // For Chars  
Debug.WriteLine("Hello".Repeat(100)); // For Strings

โปรดทราบว่าการทดสอบประสิทธิภาพของการใช้รุ่น stringbuilder สำหรับตัวอักษรง่าย ๆ แทนที่จะเป็นสตริงจะช่วยให้คุณมีบทลงโทษที่สำคัญที่สุด: บนคอมพิวเตอร์ของฉันความแตกต่างของประสิทธิภาพการทำงานที่มีค่าคือ 1:20 ระหว่าง: Debug.WriteLine ('-' ทำซ้ำ (1000000)) // รุ่น char และ
Debug.WriteLine ("-" ทำซ้ำ (1000000)) // รุ่นสตริง


2
ประสิทธิภาพการทำงานของรุ่นสตริงอาจจะดีขึ้นโดยใช้StringBuilder.Insert(Int32, String, Int32)เป็นBinoj แอนโทนี่ตอบ
Palec

23

เกี่ยวกับสิ่งนี้:

//Repeats a character specified number of times
public static string Repeat(char character,int numberOfIterations)
{
    return "".PadLeft(numberOfIterations, character);
}

//Call the Repeat method
Console.WriteLine(Repeat('\t',40));

4
ฮ่าฮ่า .. นั่นคือสิ่งที่ฉันสามารถนึกได้เมื่อฉันตกอยู่ในสถานการณ์เช่นนี้อีกครั้ง แต่โดยส่วนตัวฉันพบว่าnew string('\t', 10)เป็นทางออกที่ดีที่สุด
shashwat

เคล็ดลับนี้ยังใช้ในการระเหย C # 6.0
โปรแกรมเมอร์ที่มุ่งเน้นเงินใน

22

ฉันรู้ว่าคำถามนี้มีอายุห้าปีแล้ว แต่มีวิธีง่ายๆในการทำซ้ำสตริงที่ใช้งานได้ใน. Net 2.0

ในการทำซ้ำสตริง:

string repeated = new String('+', 3).Replace("+", "Hello, ");

ผลตอบแทน

"สวัสดีสวัสดีสวัสดี"

ในการทำซ้ำสตริงเป็นอาร์เรย์:

// Two line version.
string repeated = new String('+', 3).Replace("+", "Hello,");
string[] repeatedArray = repeated.Split(',');

// One line version.
string[] repeatedArray = new String('+', 3).Replace("+", "Hello,").Split(',');

ผลตอบแทน

{"Hello", "Hello", "Hello", ""}

ง่าย ๆ เข้าไว้.


19

สมมติว่าคุณต้องการทำซ้ำ '\ t' จำนวนครั้งคุณสามารถใช้;

String.Empty.PadRight(n,'\t')

1
ขอบคุณ นี่ยังเร็วมาก codereview.stackexchange.com/questions/36391/…
Sunsetquest

ฉันทำแบบนี้มาตลอด แม้ว่าจะถูกหุ้มด้วยวิธีการขยายมันง่ายกว่าการใช้งานอื่น ๆ ที่โพสต์ที่นี่ โปรดทราบว่า OP ต้องการเพียงแค่ทำซ้ำ \ t ไม่ใช่สตริง
Michael Ribbons

17

ตัวอย่างแรกของคุณที่ใช้Enumerable.Repeat:

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat(
                                 "\t", (int) numTabs);
    return (numTabs > 0) ? 
            tabs.Aggregate((sum, next) => sum + next) : ""; 
} 

สามารถเขียนใหม่ดานกับString.Concat:

private string Tabs(uint numTabs)
{       
    return String.Concat(Enumerable.Repeat("\t", (int) numTabs));
}

14

การใช้String.ConcatและEnumerable.Repeatซึ่งจะมีราคาแพงน้อยกว่าการใช้String.Join

public static Repeat(this String pattern, int count)
{
    return String.Concat(Enumerable.Repeat(pattern, count));
}


4

คำตอบนั้นขึ้นอยู่กับความซับซ้อนที่คุณต้องการ ตัวอย่างเช่นฉันต้องการจัดเค้าร่างการเยื้องทั้งหมดของฉันด้วยแถบแนวตั้งดังนั้นสตริงการเยื้องของฉันจะถูกกำหนดดังนี้:

return new string(Enumerable.Range(0, indentSize*indent).Select(
  n => n%4 == 0 ? '|' : ' ').ToArray());

3

และอีกวิธีหนึ่ง

new System.Text.StringBuilder().Append('\t', 100).ToString()

การส่งผ่านความยาวสตริงที่ได้ไปยังStringBuilderconstructor จะบันทึกการจัดสรรใหม่ ถึงกระนั้นมันก็ช่างพูดมากขึ้นและมีประสิทธิภาพน้อยกว่าการใช้ตัวstringสร้างที่สามารถทำซ้ำอักขระที่กำหนดดังที่แสดงในคำตอบที่ยอมรับแล้ว
Palec

3

สำหรับฉันสบายดี:

public static class Utils
{
    public static string LeftZerosFormatter(int zeros, int val)
    {
        string valstr = val.ToString();

        valstr = new string('0', zeros) + valstr;

        return valstr.Substring(valstr.Length - zeros, zeros);
    }
}

2

คุณสามารถสร้างวิธีการขยาย

static class MyExtensions
{
    internal static string Repeat(this char c, int n)
    {
        return new string(c, n);
    }
}

จากนั้นคุณสามารถใช้มันเช่นนี้

Console.WriteLine('\t'.Repeat(10));

1

ไม่ต้องสงสัยเลยว่าคำตอบที่ยอมรับนั้นเป็นวิธีที่ดีที่สุดและเร็วที่สุดในการทำซ้ำอักขระเดี่ยว

คำตอบของ Binoj Anthony เป็นวิธีที่ง่ายและมีประสิทธิภาพในการทำซ้ำสตริง

อย่างไรก็ตามถ้าคุณไม่สนใจรหัสอีกเล็กน้อยคุณสามารถใช้เทคนิคการเติมอาร์เรย์ของฉันเพื่อสร้างสตริงเหล่านี้ได้เร็วขึ้น ในการทดสอบเปรียบเทียบของฉันรหัสด้านล่างดำเนินการในประมาณ 35% ของเวลาของรหัส StringBuilder.Insert

public static string Repeat(this string value, int count)
{
    var values = new char[count * value.Length];
    values.Fill(value.ToCharArray());
    return new string(values);
}

public static void Fill<T>(this T[] destinationArray, params T[] value)
{
    if (destinationArray == null)
    {
        throw new ArgumentNullException("destinationArray");
    }

    if (value.Length > destinationArray.Length)
    {
        throw new ArgumentException("Length of value array must not be more than length of destination");
    }

    // set the initial array value
    Array.Copy(value, destinationArray, value.Length);

    int copyLength, nextCopyLength;

    for (copyLength = value.Length; (nextCopyLength = copyLength << 1) < destinationArray.Length; copyLength = nextCopyLength)
    {
        Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
    }

    Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
}

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเทคนิคการเติมอาเรย์นี้ให้ดูวิธีที่เร็วที่สุดในการเติมอาเรย์ด้วยค่าเดียว


0

ลองสิ่งนี้:

  1. เพิ่ม Microsoft.VisualBasic การอ้างอิง
  2. ใช้: ผลสตริง = Microsoft.VisualBasic.Strings.StrDup (5, "hi");
  3. แจ้งให้เราทราบว่าเหมาะกับคุณหรือไม่

การเพิ่มการพึ่งพาแอสเซมบลีอื่นและความต้องการโหลดจะไม่มีเหตุผลในกรณีส่วนใหญ่เมื่อคุณต้องการฟังก์ชันการทำงานดังกล่าว ยังดีที่รู้ว่ามีสิ่งดังกล่าวใน. NET
Palec

มีข้อดีและข้อเสียมากมายในบริบทที่แตกต่างกันดังนั้นทุกคนควรตัดสินใจโดยขึ้นอยู่กับสถานการณ์ที่เขา / เขาอยู่
Toso Pankovski

-1

แม้ว่าจะคล้ายกับข้อเสนอแนะก่อนหน้านี้ฉันต้องการทำให้มันง่ายและใช้สิ่งต่อไปนี้:

string MyFancyString = "*";
int strLength = 50;
System.Console.WriteLine(MyFancyString.PadRight(strLength, "*");

มาตรฐาน. Net จริงๆ


มันจะเพิ่มการขยายไม่ซ้ำ
levi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.