Best Way to Repeat a Character in C#

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



























































































MethodNTemplateMeanErrorStdDevGen 0Code SizeGen 1Allocated
Original512Squirrel259.812 μs9.2615 μs12.0425 μs252.44141 KB12.20702,064 KB
Create512Squirrel2.471 μs0.0796 μs0.1089 μs0.98801 KB0.02868 KB
StringBuilder512Squirrel5.197 μs0.1162 μs0.1511 μs2.03702 KB0.114417 KB
ArrayConcat512Squirrel5.114 μs0.0994 μs0.1257 μs1.47251 KB0.053412 KB
ConcatStringBuilder512Squirrel9.304 μs0.0982 μs0.0919 μs2.02943 KB0.106817 KB
Concat512Squirrel5.284 μs0.0376 μs0.0334 μs0.98424 KB0.02298 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



Leave a reply



Submit