Найкращий спосіб повторити символ у C #


812

Що це найкращий спосіб створити рядок \ts у C #

Я вивчаю C # і експериментую з різними способами сказати одне і те ж.

Tabs(uint t)це функція, яка повертає a 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; 
}

Відповіді:


1490

Як що до цього:

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

Повертається

"абаб"

І

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

Повертається

"аа"

від ...

Чи є вбудована функція для повторення рядка або знаку в .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
@Pharap string.Joinбув швидшим у прикладі, оскільки вони використовували роздільник місця. string.Concatпідходить, коли немає роздільника.
Картер Медлін

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 Чи знаєте ви, чи хтось пояснив, чому інші відповіді гірші? Я б припустив, що рідний String.Concat буде настільки ж оптимізований внутрішньо, як StringBuilder
Marie

@Marie У наступній статті пояснюються деякі переваги. support.microsoft.com/en-au/help/306822/… Інакше два інші фактори: StringBuilder дозволяє створювати рядки і не обмежуються лише знаком (хоча це не стосується початкового питання) та рядком. Відповідь Concat вище повинна створити масив спочатку за допомогою Enumerable.Repeat. Як я вже казав, це зайві накладні витрати.
середній простір

Я припускав, що спочатку не створить масив, оскільки він може просто повторювати елемент за пунктом. Дякую за посилання, я прошу прочитати!
Марі

63

Найкраща версія, звичайно, використовувати вбудований спосіб:

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

З інших рішень віддавайте перевагу найпростішому; лише якщо це виявляється занадто повільним, прагніть до більш ефективного рішення.

Якщо ви використовуєте a StringBuilderі знаєте його отриману довжину заздалегідь, а також використовуйте відповідний конструктор, це набагато ефективніше, оскільки це означає, що відбувається лише один трудомісткий розподіл, і немає зайвого копіювання даних. Дурниці: звичайно, вищезазначений код є більш ефективним.


12
sb.Append ('\ t', len);
дан-gph

7
Мої орієнтири показують, що new string('\t', len)в 2–7 разів швидше, ніж StringBuilderпідхід. Чому, на вашу думку StringBuilder, в цьому випадку ефективніше?
Стриптинг-воїн

6
@StriplingWarrior Дякуємо, що виправили це (після того, як він простояв тут вже два роки, не менше!).
Конрад Рудольф

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
Колись люди використовували циклі
прабхакаран

2
@prabhakaran Я згоден, але перевага Linq полягає в спілкуванні; майже завжди тривіально повторювати вираз Linq за допомогою імперативних конструкцій.
Родрік Чапман

10
Enumerable.Range(0, n).SelectMany(x => s)можна замінити простим Enumerable.Repeat(s, n).
Палець

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)). Це вже було розміщено раніше .
Палець

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), як відповів Біной Ентоні .
Палець

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

Цей трюк також використовується в Essential 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(',');

Повертається

{"Привіт привіт привіт", ""}

Не ускладнювати.


19

Скажімо, ви хочете повторити '\ t' n кількість разів, ви можете використовувати;

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

1
Дякую. Це теж дуже швидко. codereview.stackexchange.com/questions/36391/…
Sunsetquest

Я завжди робив це так. Навіть якщо він розгорнутий у методі розширення, він простіший за інші розміщені тут програми. Зауважте, що OP просто хотів повторити \ t, а не рядки.
Майкл Стрічки

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

9
var str = new string(Enumerable.Repeat('\t', numTabs).ToArray());

4

Відповідь дійсно залежить від потрібної вам складності. Наприклад, я хочу окреслити всі мої відступи вертикальною смугою, тому мій рядок відступу визначається наступним чином:

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

3

І ще один метод

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

Передача отриманої довжини рядка на StringBuilderконструктор економить перерозподіл. Все-таки це частіше і менш ефективно, ніж використання stringконструктора, який може повторити заданий символ, як уже показано у прийнятій відповіді.
Палець

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

Без сумніву, прийнята відповідь - найкращий і найшвидший спосіб повторити один символ.

Відповідь Біной Ентоні - простий і досить ефективний спосіб повторити рядок.

Однак, якщо ви не заперечуєте трохи більше коду, ви можете використовувати мою техніку заповнення масиву, щоб ефективно створити ці рядки ще швидше. У моїх тестах порівняння код, виконаний нижче, виконується приблизно за 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. Використання: String result = Microsoft.VisualBasic.Strings.StrDup (5, "привіт");
  3. Дайте мені знати, чи працює це для вас.

Додавання залежності від іншої збірки та необхідність завантажувати її є недоцільним у більшості випадків, коли вам потрібна така функціональність. І все-таки добре знати, що в .NET є таке.
Палець

У різних контекстах багато плюсів і мінусів, тому кожен повинен вирішувати залежно від ситуації, в якій він знаходиться.
Тосо Паньковський

-1

Хоча я дуже схожа на попередню пропозицію, я люблю робити її простою і застосовувати наступне:

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

Стандарт.


Це просто додасть набивання, не повторюється
levi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.