Best way to repeat a character in C#
What about this:
string tabs = new string('\t', n);
Where n
is the number of times you want to repeat the string.
Or better:
static string Tabs(int n)
{
return new string('\t', n);
}
Is there an easy way to return a string repeated X number of times?
If you only intend to repeat the same character you can use the string constructor that accepts a char and the number of times to repeat it new String(char c, int count)
.
For example, to repeat a dash five times:
string result = new String('-', 5);
Output: -----
How to repeat a set of characters
A slight variation on the answer by Bala R
var s = String.Concat(Enumerable.Repeat("-.", 10));
Is there a built-in function to repeat a string or char in .NET?
string.Join("", Enumerable.Repeat("ab", 2));
Returns
"abab"
And
string.Join("", Enumerable.Repeat('a', 2))
Returns
"aa"
How to repeat each char in string and return new string with repeated chars?
Using the string indexer
using System.Text;
public static string Repeat(string str, int count)
{
StringBuilder builder = new StringBuilder(str.Length * count);
for ( int index = 0; index < str.Length; index++ )
builder.Append(str[index], count);
return builder.ToString();
}
Fiddle Snippet
Test
string str = "Back";
int count = 3;
var result = Repeat(str, count);
Console.WriteLine(result);
Output
BBBaaaccckkk
Using an extension method with the string char enumerator
static public class StringHelper
{
static public string RepeatEachChar(this string str, int count)
{
StringBuilder builder = new StringBuilder(str.Length * count);
foreach ( char c in str )
builder.Append(c, count);
return builder.ToString();
}
}
Console.WriteLine("Back".RepeatEachChar(3));
How to print the same character many times with Console.WriteLine()
You can use the string
constructor:
Console.WriteLine(new string('.', 10));
Initializes a new instance of the String class to the value indicated
by a specified Unicode character repeated a specified number of times.
Faster way to repeat a string N times
TL;DR:
String.Create()
is fastest, scroll down. But anything other than+=
cuts mustard, and are all close enough that it doesn't really matter.
"Looking" unoptimized and being unoptimized are two very different things. However, in this case, you're right, and for several reasons.
string += string
is compiled down to String.Concat(string, string)
, and that roughly equates to:
String result = FastAllocateString(str0Length + str1.Length);
FillStringChecked(result, 0, str0);
FillStringChecked(result, str0Length, str1);
return result;
Which allocates a new string, copies the existing string over, and then adds the new value to the end. Not helpful! Now, for every loop iteration, we're discarding the old string (increasing GC pressure), and we're also copying the existing concatenations to the new one. This makes +=
a very expensive operator to use. In our case, it allocates 100x more memory (see below) than alternative methods.
[Benchmark]
public static string Original(string str, int n)
{
string s = "";
for (int i = 0; i < n; i++)
s += str;
// ^^
// BZZT! reallocation!
// *in* the loop body, not out of it!
return s;
}
Now, let's look at the alternatives.
StringBuilder
[Benchmark]
public string StringBuilder()
{
System.Text.StringBuilder b = new StringBuilder();
for (int i = 0; i < N; i++)
b.Append( Template );
return b.ToString();
}
The source of Append
is less straightforward than Concat
, but boils down to roughly:
// heavily trimmed for brevity
if (chunkLen + valueLen < chunkChars.Length)
Buffer.Memmove(
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(chunkChars), chunkLength),
ref value.GetRawStringData(),
(nuint)valueLen);
else
AppendHelper(value);
This is much better than the original, because instead of reallocating the string, it uses the existing buffer it has, and simply copies to the end of that, like a good Append method should!
String.Concat(IEnumerable)
[Benchmark]
public string Concat()
{
return String.Concat(Enumerable.Repeat(Template, N));
}
Wait, how could this be better? An Enumerable can't tell you how long it'll be! Wouldn't it have to do the same expand-copy tactic as the StringBuilder? And the answer is no: Allocations are chunked, and grow exponentially, meaning multiple iterations of the Enumerable can share the same allocation (internally it uses a ValueStringBuilder
which is similar to a StringBuilder
). It's not as good, but it certainly helps.
Note: This is the most memory efficient method, see below.
// trimmed for brevity
var result = new ValueStringBuilder();
do
{
result.Append(en.Current);
}
while (en.MoveNext());
return result.ToString();
String.Concat(string[])
And here, we stumble upon the perfect solution, or at least so I thought.
With this concatenation method, C# calculates the maximum size of the string upfront, meaning minimal allocations and one looped copy. Glorious!
(The one downside is you have to provide it with an array. Luckily, strings are references, so this is sorta fast too.)
[Benchmark]
public string ArrayConcat()
{
string[] list = new string[N];
for (int i = 0; i < N; i++)
list[i] = Template;
return String.Concat(list);
}
Note: This is not the most memory efficient method, because it allocated 4KB for the
list
!
String.Create()
The lovely @Charlieface has showed me the wrong of my ways, and introduced me to String.Create
. Modifying their example source code, I was able to achieve a whopping 2.4 microsecond copy time, putting it so solidly in first place I had to triple-check it was working properly.
[Benchmark]
public string Create()
{
return String.Create(Template.Length * N, Template, RepeatFromString);
}
This is likely because string.create
does not need to loop or have an array allocated and filled--It's a clean copy!
Shut up and show me the numbers
Method | N | Template | Mean | Error | StdDev | Gen 0 | Code Size | Gen 1 | Allocated |
---|---|---|---|---|---|---|---|---|---|
Original | 512 | Squirrel | 259.812 μs | 9.2615 μs | 12.0425 μs | 252.4414 | 1 KB | 12.2070 | 2,064 KB |
Create | 512 | Squirrel | 2.471 μs | 0.0796 μs | 0.1089 μs | 0.9880 | 1 KB | 0.0286 | 8 KB |
StringBuilder | 512 | Squirrel | 5.197 μs | 0.1162 μs | 0.1511 μs | 2.0370 | 2 KB | 0.1144 | 17 KB |
ArrayConcat | 512 | Squirrel | 5.114 μs | 0.0994 μs | 0.1257 μs | 1.4725 | 1 KB | 0.0534 | 12 KB |
ConcatStringBuilder | 512 | Squirrel | 9.304 μs | 0.0982 μs | 0.0919 μs | 2.0294 | 3 KB | 0.1068 | 17 KB |
Concat | 512 | Squirrel | 5.284 μs | 0.0376 μs | 0.0334 μs | 0.9842 | 4 KB | 0.0229 | 8 KB |
String interpolation - repeat
public static string Repeat(this string s, int times, string separator = "")
{
return string.Join(separator, Enumerable.Repeat(s, times));
}
Then use:
Console.WriteLine($"foo {name.Repeat(2)} bar")
Is there a LINQ-way to append the same character n-times to a string?
You can use Enumerable.Repeat
in String.Concat
:
string intend = String.Concat(Enumerable.Repeat(sequence, n));
If you just want to repeat a single character you should prefer the String
-constructor:
string intend = new String('\t', n);
Related Topics
Web Reference VS. Service Reference
Attach a File from Memorystream to a Mailmessage in C#
Execute Multiple Command Lines with the Same Process Using .Net
How to Get the File Size from Http Headers
Using Filesystemwatcher to Monitor a Directory
Why Should I Prefer Single 'Await Task.Whenall' Over Multiple Awaits
C# Is Rounding Down Divisions by Itself
Weird Error Upgrading ASP.NET MVC from 4 to 5
Webdriverwait Is Not Waiting for the Element I Specify
Add Data Annotations to a Class Generated by Entity Framework
How to Securely Save Username/Password (Local)
Random String Generator Returning Same String
Is a Double Really Unsuitable for Money
Why Do C# Multidimensional Arrays Not Implement Ienumerable<T>
"A Project with an Output Type of Class Library Cannot Be Started Directly"