0

I am building up a string of data using substring. The format of the data I want is

[1,2,3,4,5,6,7,8,9,10]

So I am building it up as follows

StringBuilder sb = new StringBuilder();
sb.append("1,");
sb.append("2,");
sb.append("3,");
.
.
.

The problem I run into is when I want to trim the final , before adding the closing ].

I could do

sb.ToString();
sb.Substring(0, (sb.Length - 1));
sb += "]";

But using the += is not very efficient as this creates a new string. Is there a better way of doing this?

Wesley Skeen
  • 6,937
  • 12
  • 37
  • 55

5 Answers5

6
var str = "[" + String.Join(", ",Enumerable.Range(1,10)) + "]";
L.B
  • 106,644
  • 18
  • 163
  • 208
  • 3
    But it's not what OP has asked for since it creates new strings and it's also not clear that OP wants only integers between 1 and 10 even if it's the sample data. – Tim Schmelter Nov 12 '12 at 10:15
  • 1
    Thanks for this, I never knew you could do this with link. It would require a re write of my code so i won't use it now, but it is good for the future @L.B – Wesley Skeen Nov 12 '12 at 10:28
  • I like this approach even if it is not particularly performance worthy due to the creation of several strings. – Matthew Layton Nov 12 '12 at 10:28
  • @WesleySkeen, you can do it in one line without linq of course, just use `String.Format`, as in my answer. – Jodrell Nov 12 '12 at 10:32
4

Don't add the final , if you don't need it:

var sb = new StringBuilder().Append('[');
var first = true;
foreach (var item in collection)
{
    if (first)
        first = false;
    else
        sb.Append(',');
    sb.Append(item);
}
sb.Append(']');
var result = sb.ToString();
dtb
  • 198,715
  • 31
  • 379
  • 417
  • This is the most correct suggestion but the wrong code. You have to check for last one, not the first. – Sedat Kapanoglu Nov 12 '12 at 10:20
  • @ssg: I add a comma before each element except for the first one. Why is that wrong? – dtb Nov 12 '12 at 10:22
  • @dtb I thought you added comma after, sorry my bad. Then this is the proper answer. – Sedat Kapanoglu Nov 12 '12 at 10:24
  • @dtb this is the right answer. Sorry for my wrong initial interpretation :) +1ed :) – nawfal Nov 12 '12 at 10:40
  • `string.Format("[{0}]", string.Join(",", collection));` achieves the same in one line. – Jodrell Nov 12 '12 at 10:41
  • @Jodrell: Sure. But it creates a bunch of intermediate strings. That's not bad. Except if you want to avoid them. So I've proposed a solution that avoids any intermediate string. – dtb Nov 12 '12 at 10:43
  • @dtd, is that how `String.Join` and `String.Format` are implemented? Its more sophisticated than that, http://stackoverflow.com/questions/585860/string-join-vs-stringbuilder-which-is-faster – Jodrell Nov 12 '12 at 10:48
  • I did a little test, if performance really matters, this method using the `StringBuilder` directly is a little faster. I think this must be because the Join-Format method has to allocate and populate the memory twice. +1 – Jodrell Nov 12 '12 at 14:23
  • @dtb, I did a little more testing and found a `Concat` and `Join` combination is actually faster than `StringBuilder`. – Jodrell Nov 16 '12 at 12:11
3

The easiest is to use -= on the StringBuilder's Length since it's writable:

sb.Length -= 1; // removes the last char
Tim Schmelter
  • 411,418
  • 61
  • 614
  • 859
  • 1
    Wasn't the question about the `+=`? – Jodrell Nov 12 '12 at 10:17
  • 1
    @Jodrell: I'm not sure because the title mentions "using substrings properly" and "The problem I run into is when I want to trim the final , before adding the closing ]". – Tim Schmelter Nov 12 '12 at 10:18
  • This may need a check if `"[]"` is a valid result. Otherwise the opening bracket might get removed. – dtb Nov 12 '12 at 10:18
  • @dtb: Of course this needs an additonal check `if(sb.Length>1)sb.Length -= 1;` before appending the final `]`. – Tim Schmelter Nov 12 '12 at 10:21
  • 1
    Setting `.Length` copies the contents of StringBuilder buffer to another newly created array, it's not much different than `Substring` approach so definitely not efficient. Try @dtb 's answer. – Sedat Kapanoglu Nov 12 '12 at 10:36
  • 1
    @ssg: Only if the buffer is not large enough for the new length. Which is not the case if the length is decreased. – dtb Nov 12 '12 at 10:40
3

UPDATE

After a little testing

var result = string.Concat("[", string.Join(",", someEnumerable), "]");

is both much simpler and faster than a builder approach


You could always just do

var result = string.Format("[{0}]", string.Join(",", someEnumerable));

The sequence can be anything you want, for instance

var someEnumerable = Enumerable.Range(1, 10);

This seems simpler than reinventing the wheel, and avoids intermediate strings.

This does make assumptions about the implementation of String.Join but, I think you should assume that its good enough for this purpose.


For more information, this Question does a comparison between String.Join and StringBuilder.

This Question indicates that String.Format uses a StringBuilder.

Community
  • 1
  • 1
Jodrell
  • 31,518
  • 3
  • 75
  • 114
  • 1
    Whilst it was not me that downvoted, the code does not work. It should be string.Join(",", someEnumerable)); – Matthew Layton Nov 12 '12 at 10:32
  • 1
    Also I do not know if this is creating multiple strings behind the scenes. – Matthew Layton Nov 12 '12 at 10:32
  • @activwerx, doh, fixed the ommited parameter. You are right, I don't know how `String.Join` is implemented either but, I should assume that its has been provided for a reason. – Jodrell Nov 12 '12 at 10:36
  • Well I've removed the downvote as I think this is a good implementation! :-) – Matthew Layton Nov 12 '12 at 10:36
  • `Any comments downvoters?` that sounded so audacious when you know it why you were. Editing a wrong answer and then questioning back masks nothing. SO is so transparent. While I was one downvoter, I removed it now. – nawfal Nov 12 '12 at 10:43
  • @nawfal I can't catch the exceptions unless they are thrown. I grant that the answer as evolved somewhat but, thats the idea, right? – Jodrell Nov 12 '12 at 10:46
  • @Jodrell yes thats alright. The way you phrased it made it look like you're so sure there's nothing wrong with your answer :) – nawfal Nov 12 '12 at 11:03
1

Here is an example as a nice clean method:

    public static string WriteValues(int start, int end)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("[");
        for (int index = start; index <= end; index++)
        {
            sb.Append(index).Append(",");
        }
        sb.Length -= 1;
        sb.Append("]");
        return sb.ToString();
    }

This does all the work in the StringBuilder and then passes back a single string. Also you can specify the start and end values!

Matthew Layton
  • 32,574
  • 37
  • 140
  • 255