Как лучше всего сгенерировать строку \t на C#
Я изучаю C# и экспериментирую с разными способами выразить одно и то же.
Tabs(uint t) - это функция, которая возвращает string с количеством t из \t.
Например, Tabs(3) возвращает "\t\t\t".
Какой из этих трех способов реализации Tabs(uint numTabs) лучше всего?
Конечно, это зависит от того, что означает «лучший».
Версия LINQ состоит всего из двух строк, что приятно. Но являются ли вызовы Repeat и Aggregate излишними затратами времени / ресурсов?
Версия StringBuilder очень ясна, но класс StringBuilder как-то медленнее?
Версия string является базовой, а значит, ее легко понять.
Это вообще не имеет значения? Все ли они равны?
Все эти вопросы помогут мне лучше понять 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;
}





Как насчет этого:
string tabs = new String('\t', n);
Где n - это количество раз, которое вы хотите повторить строку.
Или лучше:
static string Tabs(int n)
{
return new String('\t', n);
}
@ user1478137 Или лучше (тоже ниже): это
Лучшая версия, безусловно, - использовать встроенный способ:
string Tabs(int len) { return new string('\t', len); }
Из других решений отдавайте предпочтение самому простому; только если это оказывается слишком медленным, стремитесь к более эффективному решению.
Если вы используете
Ерунда: конечно, приведенный выше код более эффективен.StringBuilder и заранее знаете его результирующую длину, тогда также используйте соответствующий конструктор, это намного эффективнее, потому что это означает, что выполняется только одно трудоемкое выделение, и никакого ненужного копирования данных.
Мои тесты показывают, что new string('\t', len) в 2-7 раз быстрее, чем подход StringBuilder. Как вы думаете, почему в этом случае StringBuilder более эффективен?
@StriplingWarrior Спасибо, что исправили это (после того, как он простоял здесь два года, не меньше!).
А как насчет использования метода расширения?
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
Обратите внимание, что проверка производительности с использованием версии конструктора строк для простых символов вместо строк дает вам серьезную штрафную санкцию за выполнение:
на моем компьютере разница в измеренной производительности составляет 1:20 между:
Debug.WriteLine ('-'. Repeat (1000000)) // версия символа и
Debug.WriteLine ("-". Repeat (1000000)) // строковая версия
Производительность строковой версии можно улучшить, используя StringBuilder.Insert(Int32, String, Int32), как Биной Энтони ответил.
Во всех версиях .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.
Это, безусловно, самая быстрая производительность для String. Другие методы создают слишком много накладных расходов.
@midspace Знаете ли вы, объяснял ли кто-нибудь, почему другие ответы хуже? Я бы предположил, что собственный String.Concat будет так же оптимизирован внутри, как StringBuilder.
@Marie В следующей статье объясняются некоторые достоинства. support.microsoft.com/en-au/help/306822/… В противном случае два других фактора: StringBuilder допускает строки и не ограничивается только символом (хотя это не относится к исходному вопросу), и ответ string.Concat выше должен сначала создать массив с помощью Enumerable.Repeat. Как я уже сказал, это лишние накладные расходы.
Я предполагал, что сначала он не создаст массив, потому что он может просто перебирать элемент за элементом. Спасибо за ссылку, дам прочтение!
Ответ действительно зависит от желаемой сложности. Например, я хочу обвести все свои отступы вертикальной чертой, поэтому моя строка отступа определяется следующим образом:
return new string(Enumerable.Range(0, indentSize*indent).Select(
n => n%4 == 0 ? '|' : ' ').ToArray());
Методы расширения:
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);
}
Enumerable.Range(0, n).SelectMany(x => s) можно заменить простым Enumerable.Repeat(s, n).
@Palec Нет, не может. SelectMany будет для каждого одиночного фиктивного x давать последовательность значений char (поскольку string s реализует IEnumerable<char>), и все эти последовательности char объединены в одну длинную последовательность char. То, что вы предлагаете, вместо этого даст IEnumerable<string>. Это не то же самое.
Я был неправ, @JeppeStigNielsen. Спасибо за предупреждение. Если бы я действительно хотел использовать Enumerable.Repeat, мне пришлось бы объединить строки вместе: string.Concat(Enumerable.Repeat(s, n)). Это уже было опубликовано ранее.
Ваш первый пример, в котором используется 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));
}
Как насчет этого:
//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));
ха-ха ... вот что я мог подумать, когда однажды попал в такую ситуацию. Но лично я считаю new string('\t', 10) лучшим решением.
string.Concat(Enumerable.Repeat("ab", 2));
Возврат
"abab"
А также
string.Concat(Enumerable.Repeat("a", 2));
Возврат
"aa"
из...
Есть ли встроенная функция для повторения строки или символа в .net?
Сделайте это лучше, сделав это без Linq и с StruingBuilder!
'StringBuilder' не обязательно быстрее stackoverflow.com/questions/585860/…
Возможно, он не будет быстрее, но он может сэкономить на выделении памяти (давление), если вы укажете правильную емкость заранее, и это может быть так же важно, как микротест для профилирования.
var strRepeat = string.Concat (Enumerable.Repeat ("ABC", 1000000)); // 50 мс
Использование String.Concat и Enumerable.Repeat, которые будут дешевле
чем использование String.Join
public static Repeat(this String pattern, int count)
{
return String.Concat(Enumerable.Repeat(pattern, count));
}
Допустим, вы хотите повторить '\ t' n раз, вы можете использовать;
String.Empty.PadRight(n,'\t')
Спасибо. Это тоже очень быстро. codereview.stackexchange.com/questions/36391/…
Я всегда так поступал. Даже если он заключен в метод расширения, он проще, чем другие реализации, размещенные здесь. Обратите внимание, что OP просто хотел повторить \ t, а не строки.
var str = new string(Enumerable.Repeat('\t', numTabs).ToArray());
Я знаю, что этому вопросу уже пять лет, но есть простой способ повторить строку, которая работает даже в .Net 2.0.
Чтобы повторить строку:
string repeated = new String('+', 3).Replace("+", "Hello, ");
Возврат
"Hello, Hello, 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", ""}
Будь проще.
Попробуй это:
Добавлять зависимость от другой сборки и загружать ее в большинстве случаев нецелесообразно. Тем не менее, хорошо знать, что в .NET есть такая вещь.
В разных контекстах есть много плюсов и минусов, поэтому каждый должен выбирать в зависимости от ситуации, в которой он / она находится.
И еще один метод
new System.Text.StringBuilder().Append('\t', 100).ToString()
Передача результирующей длины строки в конструктор StringBuilder сохраняет перераспределение. Тем не менее, это более разговорчиво и менее эффективно, чем использование конструктора string, который может повторять заданный символ, как уже показано в принятом ответе.
Вы можете создать метод расширения
static class MyExtensions
{
internal static string Repeat(this char c, int n)
{
return new string(c, n);
}
}
Тогда вы можете использовать это так
Console.WriteLine('\t'.Repeat(10));
Для меня это нормально:
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);
}
}
Без сомнения, принятый ответ - это лучший и самый быстрый способ повторить один символ.
Ответ Биноя Энтони - простой и довольно эффективный способ повторить строку.
Однако, если вы не возражаете против того, чтобы немного больше кода, вы можете использовать мою технику заполнения массива, чтобы эффективно создавать эти строки еще быстрее. В моих сравнительных тестах приведенный ниже код выполнялся примерно в 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);
}
Дополнительные сведения об этой технике заполнения массива см. В разделе Самый быстрый способ заполнить массив одним значением.
Хотя это очень похоже на предыдущее предложение, мне нравится сохранять его простым и применять следующее:
string MyFancyString = "*";
int strLength = 50;
System.Console.WriteLine(MyFancyString.PadRight(strLength, "*");
Стандартный .Net действительно,
Он просто добавит отступ, не повторяется
@levi: В чем проблема с заполнением? string result = string.Empty.PadRight('\t',5) не возвращает желаемый результат (в данном случае 5 вкладок)?
Заполните экран 6435 z $ str = [System.Linq.Enumerable] :: Repeat ([строка] :: new ("z", 143), 45)
$ str
есть ли способ повторить это за слово? вместо "\ t" как использовать "время"