HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpModerate

Expanding a string to a certain length

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
lengthcertainstringexpanding

Problem

I wrote a function for repeating a string to a certain length.

For example:

ExpandString("Test", 11); 

// output: "TestTestTes"


Are there any optimizations or fixes that can be done to this function?

private string ExpandString(string str, int length)
{
    if (length <= str.Length) return str.Substring(0, length);
    var result = str;
    for (var i = str.Length; i < length; i++)
    {
        result += str[i % str.Length];
    }
    return result;
}

Solution

OK, first, for the most straightforward optimization. Use a StringBuilder.

The way your code currently works, it creates length - str.Length intermediate strings. Besides creating lots of unnecessary garbage, you're copying longer and longer strings over and over again to add one character each time.

If you use a StringBuilder instead, you can avoid most of those copies.
You could try something like...

using System.Text;

...

private string ExpandString(string str, int length)
{
    if (length <= str.Length) return str.Substring(0, length);
    var result = new StringBuilder(str);
    for (var i = str.Length; i < length; i++)
    {
        result.Append(str[i % str.Length]);
    }
    return result.ToString();
}


(I don't particularly like the StringBuilder starting with a copy of str already in it. I'm literally just replacing the String.)

But you're also copying one character at a time. While this isn't as big an issue as the concatenation, you can do better by inserting as many whole copies of str as you can.

private string ExpandString(string str, int length)
{
    // BTW, you already know how big the result should be, so just
    // tell the StringBuilder its capacity to prevent unneeded resizes.
    // Side benefit: if the result is too long, you'll find out fairly quickly.
    var result = new StringBuilder(length, length);

    var wholeCopies = length / str.Length;
    for (var i = 0; i < wholeCopies; ++i)
    {
        result.Append(str);
    }

    // now append the last chunk, a possibly-zero-length prefix of `str`
    result.Append(str, 0, length % str.Length);

    return result.ToString();
}


Note that the short-string optimization has been removed. You can add it back in if you really really want to micro-optimize, but at this point, it's not gaining you nearly as much as it was.

Code Snippets

using System.Text;

...

private string ExpandString(string str, int length)
{
    if (length <= str.Length) return str.Substring(0, length);
    var result = new StringBuilder(str);
    for (var i = str.Length; i < length; i++)
    {
        result.Append(str[i % str.Length]);
    }
    return result.ToString();
}
private string ExpandString(string str, int length)
{
    // BTW, you already know how big the result should be, so just
    // tell the StringBuilder its capacity to prevent unneeded resizes.
    // Side benefit: if the result is too long, you'll find out fairly quickly.
    var result = new StringBuilder(length, length);

    var wholeCopies = length / str.Length;
    for (var i = 0; i < wholeCopies; ++i)
    {
        result.Append(str);
    }

    // now append the last chunk, a possibly-zero-length prefix of `str`
    result.Append(str, 0, length % str.Length);

    return result.ToString();
}

Context

StackExchange Code Review Q#90220, answer score: 12

Revisions (0)

No revisions yet.