Expanding a string to a certain length












7












$begingroup$


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









share|improve this question











$endgroup$












  • $begingroup$
    Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
    $endgroup$
    – Franck
    May 12 '15 at 11:45












  • $begingroup$
    @Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
    $endgroup$
    – KeyBored
    May 13 '15 at 2:22
















7












$begingroup$


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









share|improve this question











$endgroup$












  • $begingroup$
    Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
    $endgroup$
    – Franck
    May 12 '15 at 11:45












  • $begingroup$
    @Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
    $endgroup$
    – KeyBored
    May 13 '15 at 2:22














7












7








7





$begingroup$


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









share|improve this question











$endgroup$




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






c# strings






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 9 '15 at 1:41









Jamal

30.3k11117227




30.3k11117227










asked May 9 '15 at 1:13









KeyBoredKeyBored

5317




5317












  • $begingroup$
    Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
    $endgroup$
    – Franck
    May 12 '15 at 11:45












  • $begingroup$
    @Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
    $endgroup$
    – KeyBored
    May 13 '15 at 2:22


















  • $begingroup$
    Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
    $endgroup$
    – Franck
    May 12 '15 at 11:45












  • $begingroup$
    @Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
    $endgroup$
    – KeyBored
    May 13 '15 at 2:22
















$begingroup$
Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
$endgroup$
– Franck
May 12 '15 at 11:45






$begingroup$
Can be sone by simply expanding on enumerable 1 step further and taking a substring for the amount needed like so : return string.IsNullOrEmpty(str) ? "".PadLeft(length,' ') : string.Join("", Enumerable.Repeat(str, (int)Math.Ceiling((double)length / (double)str.Length)).ToArray()).Substring(0, length);
$endgroup$
– Franck
May 12 '15 at 11:45














$begingroup$
@Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
$endgroup$
– KeyBored
May 13 '15 at 2:22




$begingroup$
@Franck Thanks, but the performance won't be better than any of the suggested answers. it'll be good only for one-liner functions fans. (btw, I'm one of them sometimes :))
$endgroup$
– KeyBored
May 13 '15 at 2:22










4 Answers
4






active

oldest

votes


















6












$begingroup$

Instead of adding a character at a time, double the string as long as you can without making it too long, then just add the rest of the characters:



private static string ExpandString(string str, int length) {
if (length <= str.Length) return str.Substring(0, length);
while (str.Length * 2 <= length) {
str += str;
}
if (str.Length < length) {
str += str.Substring(0, length - str.Length);
}
return str;
}


You don't need a StringBuilder for this. This method is actually almost twice as fast as using a StringBuilder.



Here is the result for a test run of calling ExpandString("Test", 100) 100000 times each, for the orginal method, the method suggested by cHao, and the method suggested above:



Original:      00:00:00.5795951
StringBuilder: 00:00:00.0372573
This: 00:00:00.0204482





share|improve this answer









$endgroup$













  • $begingroup$
    I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
    $endgroup$
    – KeyBored
    May 10 '15 at 0:40






  • 1




    $begingroup$
    @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
    $endgroup$
    – Guffa
    May 10 '15 at 10:23












  • $begingroup$
    Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
    $endgroup$
    – cHao
    May 11 '15 at 20:49












  • $begingroup$
    @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21










  • $begingroup$
    see the functions and test results here: ideone.com/KanNgz
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21



















11












$begingroup$

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.






share|improve this answer











$endgroup$













  • $begingroup$
    I wouldn't bother with the str.Substring() special cases anymore.
    $endgroup$
    – 200_success
    May 9 '15 at 3:19










  • $begingroup$
    @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
    $endgroup$
    – cHao
    May 9 '15 at 3:46





















4












$begingroup$

I will not repeat what's been said in the other review, but I would like to share an alternative approach.



First, we know the length of the return string, so we create a char array which we'll pass to the (Char) string ctor in the return statement.



var chars = new Char[length];


Next, populate the array by using the modulus operator to "translate" the chars index (the length variable in the example below) to correct str index.



while (length > 0)
{
length--;
chars[length] = str[(length % str.Length)];
}


Finally, return a new string.



return new String(chars);




Here's how the method should look like if placed in an extension class:



public static String Expand(this String value, Int32 length)
{

if (value == null)
{
throw new ArgumentNullException("value");
}
else if (length < 0)
{
throw new ArgumentOutOfRangeException("length");
}

var chars = new Char[length];

for (Int32 index = 0; (index < length); index++)
{
chars[index] = value[(index % value.Length)];
}

return new String(chars);

}





share|improve this answer









$endgroup$













  • $begingroup$
    Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
    $endgroup$
    – KeyBored
    May 9 '15 at 18:20










  • $begingroup$
    @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
    $endgroup$
    – Rick Davin
    May 21 '15 at 12:35



















0












$begingroup$

what would you do if you want to expand string to longer than Int type. say Long type?
e.g. ExpandString(string str, long length)






share|improve this answer








New contributor




Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f90220%2fexpanding-a-string-to-a-certain-length%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    6












    $begingroup$

    Instead of adding a character at a time, double the string as long as you can without making it too long, then just add the rest of the characters:



    private static string ExpandString(string str, int length) {
    if (length <= str.Length) return str.Substring(0, length);
    while (str.Length * 2 <= length) {
    str += str;
    }
    if (str.Length < length) {
    str += str.Substring(0, length - str.Length);
    }
    return str;
    }


    You don't need a StringBuilder for this. This method is actually almost twice as fast as using a StringBuilder.



    Here is the result for a test run of calling ExpandString("Test", 100) 100000 times each, for the orginal method, the method suggested by cHao, and the method suggested above:



    Original:      00:00:00.5795951
    StringBuilder: 00:00:00.0372573
    This: 00:00:00.0204482





    share|improve this answer









    $endgroup$













    • $begingroup$
      I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
      $endgroup$
      – KeyBored
      May 10 '15 at 0:40






    • 1




      $begingroup$
      @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
      $endgroup$
      – Guffa
      May 10 '15 at 10:23












    • $begingroup$
      Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
      $endgroup$
      – cHao
      May 11 '15 at 20:49












    • $begingroup$
      @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21










    • $begingroup$
      see the functions and test results here: ideone.com/KanNgz
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21
















    6












    $begingroup$

    Instead of adding a character at a time, double the string as long as you can without making it too long, then just add the rest of the characters:



    private static string ExpandString(string str, int length) {
    if (length <= str.Length) return str.Substring(0, length);
    while (str.Length * 2 <= length) {
    str += str;
    }
    if (str.Length < length) {
    str += str.Substring(0, length - str.Length);
    }
    return str;
    }


    You don't need a StringBuilder for this. This method is actually almost twice as fast as using a StringBuilder.



    Here is the result for a test run of calling ExpandString("Test", 100) 100000 times each, for the orginal method, the method suggested by cHao, and the method suggested above:



    Original:      00:00:00.5795951
    StringBuilder: 00:00:00.0372573
    This: 00:00:00.0204482





    share|improve this answer









    $endgroup$













    • $begingroup$
      I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
      $endgroup$
      – KeyBored
      May 10 '15 at 0:40






    • 1




      $begingroup$
      @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
      $endgroup$
      – Guffa
      May 10 '15 at 10:23












    • $begingroup$
      Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
      $endgroup$
      – cHao
      May 11 '15 at 20:49












    • $begingroup$
      @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21










    • $begingroup$
      see the functions and test results here: ideone.com/KanNgz
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21














    6












    6








    6





    $begingroup$

    Instead of adding a character at a time, double the string as long as you can without making it too long, then just add the rest of the characters:



    private static string ExpandString(string str, int length) {
    if (length <= str.Length) return str.Substring(0, length);
    while (str.Length * 2 <= length) {
    str += str;
    }
    if (str.Length < length) {
    str += str.Substring(0, length - str.Length);
    }
    return str;
    }


    You don't need a StringBuilder for this. This method is actually almost twice as fast as using a StringBuilder.



    Here is the result for a test run of calling ExpandString("Test", 100) 100000 times each, for the orginal method, the method suggested by cHao, and the method suggested above:



    Original:      00:00:00.5795951
    StringBuilder: 00:00:00.0372573
    This: 00:00:00.0204482





    share|improve this answer









    $endgroup$



    Instead of adding a character at a time, double the string as long as you can without making it too long, then just add the rest of the characters:



    private static string ExpandString(string str, int length) {
    if (length <= str.Length) return str.Substring(0, length);
    while (str.Length * 2 <= length) {
    str += str;
    }
    if (str.Length < length) {
    str += str.Substring(0, length - str.Length);
    }
    return str;
    }


    You don't need a StringBuilder for this. This method is actually almost twice as fast as using a StringBuilder.



    Here is the result for a test run of calling ExpandString("Test", 100) 100000 times each, for the orginal method, the method suggested by cHao, and the method suggested above:



    Original:      00:00:00.5795951
    StringBuilder: 00:00:00.0372573
    This: 00:00:00.0204482






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered May 9 '15 at 23:52









    GuffaGuffa

    6,7121327




    6,7121327












    • $begingroup$
      I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
      $endgroup$
      – KeyBored
      May 10 '15 at 0:40






    • 1




      $begingroup$
      @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
      $endgroup$
      – Guffa
      May 10 '15 at 10:23












    • $begingroup$
      Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
      $endgroup$
      – cHao
      May 11 '15 at 20:49












    • $begingroup$
      @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21










    • $begingroup$
      see the functions and test results here: ideone.com/KanNgz
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21


















    • $begingroup$
      I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
      $endgroup$
      – KeyBored
      May 10 '15 at 0:40






    • 1




      $begingroup$
      @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
      $endgroup$
      – Guffa
      May 10 '15 at 10:23












    • $begingroup$
      Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
      $endgroup$
      – cHao
      May 11 '15 at 20:49












    • $begingroup$
      @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21










    • $begingroup$
      see the functions and test results here: ideone.com/KanNgz
      $endgroup$
      – KeyBored
      May 13 '15 at 2:21
















    $begingroup$
    I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
    $endgroup$
    – KeyBored
    May 10 '15 at 0:40




    $begingroup$
    I can see that your function is slightly faster than cHao's. But how come I don't need a StringBuilder here? At least the StringBuilder will reserve the required memory space beforehand which your code doesn't.. Would you elaborate, please
    $endgroup$
    – KeyBored
    May 10 '15 at 0:40




    1




    1




    $begingroup$
    @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
    $endgroup$
    – Guffa
    May 10 '15 at 10:23






    $begingroup$
    @KeyBored: You don't need a StringBuilder because doubling the string makes it grow very quickly. The StringBuilder is slower because it still does a lot of appends, it needs 25 appends to create a 100 character string from a 4 character string. Doubling the string only needs to do 5 string concatenations. Even if the StringBuilder.Append and String.Concat calls the same method to copy the characters (wstrcpy), the overhead before it gets to that call costs just as much, so the number of calls makes the difference. With longer strings the difference is even bigger.
    $endgroup$
    – Guffa
    May 10 '15 at 10:23














    $begingroup$
    Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
    $endgroup$
    – cHao
    May 11 '15 at 20:49






    $begingroup$
    Spiffy. :) If you do this in the real world, though, i'd definitely suggest a comment or two explaining the idea.
    $endgroup$
    – cHao
    May 11 '15 at 20:49














    $begingroup$
    @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21




    $begingroup$
    @Guffa Expanding the string exponentially is a clever trick, but can I also allocate the required memory in advance as suggested in the other answers? I've tried using a StringBuilder with your code (means Append function will be called 4 times only for ExpandString("Test", 100)) but it is still slower than your function. Also allocating the memory using a new char[length] as suggested by @Bjørn works perfectly with your code and gives the best performance yet, but I'm not sure if this is the best way to go.
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21












    $begingroup$
    see the functions and test results here: ideone.com/KanNgz
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21




    $begingroup$
    see the functions and test results here: ideone.com/KanNgz
    $endgroup$
    – KeyBored
    May 13 '15 at 2:21













    11












    $begingroup$

    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.






    share|improve this answer











    $endgroup$













    • $begingroup$
      I wouldn't bother with the str.Substring() special cases anymore.
      $endgroup$
      – 200_success
      May 9 '15 at 3:19










    • $begingroup$
      @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
      $endgroup$
      – cHao
      May 9 '15 at 3:46


















    11












    $begingroup$

    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.






    share|improve this answer











    $endgroup$













    • $begingroup$
      I wouldn't bother with the str.Substring() special cases anymore.
      $endgroup$
      – 200_success
      May 9 '15 at 3:19










    • $begingroup$
      @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
      $endgroup$
      – cHao
      May 9 '15 at 3:46
















    11












    11








    11





    $begingroup$

    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.






    share|improve this answer











    $endgroup$



    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 21 '15 at 6:13

























    answered May 9 '15 at 2:37









    cHaocHao

    3,0521221




    3,0521221












    • $begingroup$
      I wouldn't bother with the str.Substring() special cases anymore.
      $endgroup$
      – 200_success
      May 9 '15 at 3:19










    • $begingroup$
      @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
      $endgroup$
      – cHao
      May 9 '15 at 3:46




















    • $begingroup$
      I wouldn't bother with the str.Substring() special cases anymore.
      $endgroup$
      – 200_success
      May 9 '15 at 3:19










    • $begingroup$
      @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
      $endgroup$
      – cHao
      May 9 '15 at 3:46


















    $begingroup$
    I wouldn't bother with the str.Substring() special cases anymore.
    $endgroup$
    – 200_success
    May 9 '15 at 3:19




    $begingroup$
    I wouldn't bother with the str.Substring() special cases anymore.
    $endgroup$
    – 200_success
    May 9 '15 at 3:19












    $begingroup$
    @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
    $endgroup$
    – cHao
    May 9 '15 at 3:46






    $begingroup$
    @200_success: Agreed. I still might get rid of it. But i did want to make sure its benefit (or rather, relative lack thereof) was addressed, rather than having someone think i just forgot it. :)
    $endgroup$
    – cHao
    May 9 '15 at 3:46













    4












    $begingroup$

    I will not repeat what's been said in the other review, but I would like to share an alternative approach.



    First, we know the length of the return string, so we create a char array which we'll pass to the (Char) string ctor in the return statement.



    var chars = new Char[length];


    Next, populate the array by using the modulus operator to "translate" the chars index (the length variable in the example below) to correct str index.



    while (length > 0)
    {
    length--;
    chars[length] = str[(length % str.Length)];
    }


    Finally, return a new string.



    return new String(chars);




    Here's how the method should look like if placed in an extension class:



    public static String Expand(this String value, Int32 length)
    {

    if (value == null)
    {
    throw new ArgumentNullException("value");
    }
    else if (length < 0)
    {
    throw new ArgumentOutOfRangeException("length");
    }

    var chars = new Char[length];

    for (Int32 index = 0; (index < length); index++)
    {
    chars[index] = value[(index % value.Length)];
    }

    return new String(chars);

    }





    share|improve this answer









    $endgroup$













    • $begingroup$
      Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
      $endgroup$
      – KeyBored
      May 9 '15 at 18:20










    • $begingroup$
      @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
      $endgroup$
      – Rick Davin
      May 21 '15 at 12:35
















    4












    $begingroup$

    I will not repeat what's been said in the other review, but I would like to share an alternative approach.



    First, we know the length of the return string, so we create a char array which we'll pass to the (Char) string ctor in the return statement.



    var chars = new Char[length];


    Next, populate the array by using the modulus operator to "translate" the chars index (the length variable in the example below) to correct str index.



    while (length > 0)
    {
    length--;
    chars[length] = str[(length % str.Length)];
    }


    Finally, return a new string.



    return new String(chars);




    Here's how the method should look like if placed in an extension class:



    public static String Expand(this String value, Int32 length)
    {

    if (value == null)
    {
    throw new ArgumentNullException("value");
    }
    else if (length < 0)
    {
    throw new ArgumentOutOfRangeException("length");
    }

    var chars = new Char[length];

    for (Int32 index = 0; (index < length); index++)
    {
    chars[index] = value[(index % value.Length)];
    }

    return new String(chars);

    }





    share|improve this answer









    $endgroup$













    • $begingroup$
      Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
      $endgroup$
      – KeyBored
      May 9 '15 at 18:20










    • $begingroup$
      @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
      $endgroup$
      – Rick Davin
      May 21 '15 at 12:35














    4












    4








    4





    $begingroup$

    I will not repeat what's been said in the other review, but I would like to share an alternative approach.



    First, we know the length of the return string, so we create a char array which we'll pass to the (Char) string ctor in the return statement.



    var chars = new Char[length];


    Next, populate the array by using the modulus operator to "translate" the chars index (the length variable in the example below) to correct str index.



    while (length > 0)
    {
    length--;
    chars[length] = str[(length % str.Length)];
    }


    Finally, return a new string.



    return new String(chars);




    Here's how the method should look like if placed in an extension class:



    public static String Expand(this String value, Int32 length)
    {

    if (value == null)
    {
    throw new ArgumentNullException("value");
    }
    else if (length < 0)
    {
    throw new ArgumentOutOfRangeException("length");
    }

    var chars = new Char[length];

    for (Int32 index = 0; (index < length); index++)
    {
    chars[index] = value[(index % value.Length)];
    }

    return new String(chars);

    }





    share|improve this answer









    $endgroup$



    I will not repeat what's been said in the other review, but I would like to share an alternative approach.



    First, we know the length of the return string, so we create a char array which we'll pass to the (Char) string ctor in the return statement.



    var chars = new Char[length];


    Next, populate the array by using the modulus operator to "translate" the chars index (the length variable in the example below) to correct str index.



    while (length > 0)
    {
    length--;
    chars[length] = str[(length % str.Length)];
    }


    Finally, return a new string.



    return new String(chars);




    Here's how the method should look like if placed in an extension class:



    public static String Expand(this String value, Int32 length)
    {

    if (value == null)
    {
    throw new ArgumentNullException("value");
    }
    else if (length < 0)
    {
    throw new ArgumentOutOfRangeException("length");
    }

    var chars = new Char[length];

    for (Int32 index = 0; (index < length); index++)
    {
    chars[index] = value[(index % value.Length)];
    }

    return new String(chars);

    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered May 9 '15 at 10:47









    Bjørn-Roger KringsjåBjørn-Roger Kringsjå

    1,22511015




    1,22511015












    • $begingroup$
      Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
      $endgroup$
      – KeyBored
      May 9 '15 at 18:20










    • $begingroup$
      @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
      $endgroup$
      – Rick Davin
      May 21 '15 at 12:35


















    • $begingroup$
      Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
      $endgroup$
      – KeyBored
      May 9 '15 at 18:20










    • $begingroup$
      @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
      $endgroup$
      – Rick Davin
      May 21 '15 at 12:35
















    $begingroup$
    Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
    $endgroup$
    – KeyBored
    May 9 '15 at 18:20




    $begingroup$
    Thanks alot.. but cHao answer gives better performance as it copies the string in chunks and avoids the letter-by-letter index calc
    $endgroup$
    – KeyBored
    May 9 '15 at 18:20












    $begingroup$
    @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
    $endgroup$
    – Rick Davin
    May 21 '15 at 12:35




    $begingroup$
    @KeyBored How do you know this was slower than StringBuilder? Did you try it with performance tests? Although generally its up to the person offering the answer to provide such timings as a way to bolster support for their answer.
    $endgroup$
    – Rick Davin
    May 21 '15 at 12:35











    0












    $begingroup$

    what would you do if you want to expand string to longer than Int type. say Long type?
    e.g. ExpandString(string str, long length)






    share|improve this answer








    New contributor




    Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






    $endgroup$


















      0












      $begingroup$

      what would you do if you want to expand string to longer than Int type. say Long type?
      e.g. ExpandString(string str, long length)






      share|improve this answer








      New contributor




      Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      $endgroup$
















        0












        0








        0





        $begingroup$

        what would you do if you want to expand string to longer than Int type. say Long type?
        e.g. ExpandString(string str, long length)






        share|improve this answer








        New contributor




        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        $endgroup$



        what would you do if you want to expand string to longer than Int type. say Long type?
        e.g. ExpandString(string str, long length)







        share|improve this answer








        New contributor




        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        share|improve this answer



        share|improve this answer






        New contributor




        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        answered 17 mins ago









        NimeshNimesh

        1




        1




        New contributor




        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        New contributor





        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        Nimesh is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f90220%2fexpanding-a-string-to-a-certain-length%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Список кардиналов, возведённых папой римским Каликстом III

            Deduzione

            Mysql.sock missing - “Can't connect to local MySQL server through socket”