Comma delimited string from list of items

Is there a simple way to create a comma delimited string from a list of items without adding an extra ", " to the end of the string?

I frequently need to take an ASP.NET CheckBoxList and format the selected values as a string for insertion into an e-mail. It's straightforward to loop over the selected checkboxes, get the values, and add them to a StringBuilder with a ", " separating them, but the Count property returns the number of items in the list total, not the number of items that are actually selected. So it's hard to know when you've reached the last item, and you end up with a stray ", " on the end.

I've played around with several different approaches to this problem. Lately I've been doing something like this:

private string ConcatenateCheckBoxListItems()
{
StringBuilder sb = new StringBuilder();
char[] characters = new char[] {" ", ","};
String trimmedString;

foreach (ListItem item in MyList)
{
sb.Append(item.Value + ", ");
}

trimmedString = sb.ToString().TrimEnd(characters);
return trimmedString;
}


But it's definitely clunky. So do the various for loop approaches I've tried. Any suggestions for a cleaner implementation?

-
Does this built-in do what you want? –  Mark Loeser Mar 3 '11 at 16:35
Despite the answers, in this code, your delimiter should be a string, and trim end should call delimiter.ToCharArray() in order to make maintenance just a tad bit easier. –  NickLarsen Mar 3 '11 at 21:25
Thanks, Nick. Good to know for other contexts. –  Josh Earl Mar 4 '11 at 12:55

Would this not suffice?

private string ConcatenateCheckBoxListItems()
{
return string.Join(", ", from item in MyList select item.Value);
}

-
Cool, how didn't I know that one. :O :) –  Steven Jeuris Mar 3 '11 at 16:42
@Steven That's the thing with the .NET Framework. You can't know it all; you only know what you've had to know. And that's why sites like this exist. –  pdr Mar 3 '11 at 16:46
I absolutely love this site. Yes, that's perfect, compact, elegant... I feel like more of a novice every day. :) –  Josh Earl Mar 3 '11 at 17:30
@thedev No, but it could easily be extended for that. Simply change the bit after select to either replace commas item.Value.Replace(",", @"\,") or surround the string in quotes item.Value.Contains(",") ? string.Format(@"""{0}""", item.Value) : item.Value. Whatever you require –  pdr Mar 3 '11 at 18:23
Python? In my C#? In all seriousness, I didn't know you could do such wizardry in C#. Great answer. –  Humphrey Bogart Mar 3 '11 at 21:33

Why not string.Join()?

var result = string.Join(", ", MyList.Items.Select(i => i.Value));

-

string.Join() is a good answer, but I prefer to create an extension method:

namespace StringExtensions
{
static class _
{
public static string JoinString<T>(this IEnumerable<T> source, string seperator = "")
{
return string.Join(seperator, source);
}
}
}


which is used like this:

return MyList.Select(i => i.Value).JoinString(", ");


(I'm using my unconventional method of organizing extension methods, which you can read about here: http://jbazuzicode.blogspot.com/2009/01/way-to-manage-extension-methods-in-c.html).

-
I have an even more unconventional method, I put them in the corresponding System namespaces. :) No need to add usings. I'm still deciding whether I'm gonna keep this practice or not. –  Steven Jeuris Mar 4 '11 at 13:52
I prefer the concept of stashing utility functions in extension methods. @Steven - I had never thought of placing my extension methods in a System namespace -- +1 –  Jeff Fritz Mar 5 '11 at 14:04
@StevenJeuris that thread gave me cancer –  DLeh Feb 27 at 20:21

As pdr has pointed out, it's best to use String.Join, instead of doing it yourself as I stated earlier.

Maybe I'm missing something, but can't you just do the following?

private string ConcatenateCheckBoxListItems()
{
StringBuilder sb = new StringBuilder();

for ( int i = 0; i < MyList.Items.Count; ++i )
{
ListItem item = MyList.Items[ i ];
sb.Append( item.Value );
if ( i < MyList.Items.Count - 1 )
{
sb.Append( ", " );
}
}

return sb.ToString();
}


UPDATE:

As a sidenote, I know it's easy to quickly lose the overview of the intent with code like this. That's why I've been working on an experimental class which allows to do the following.

StringBuilder sb = new StringBuilder();
Loop loop = Loop.ForEach( MyList.Items, i => sb.Append( i.Value ) );
loop.After.AllButLast( () => sb.Append( ", " ) );
loop.Run();


I'm still deciding whether or not I like this solution. :) Haven't used it that often.

-
This is similar to the other approach that I've tried. In this case, the number of items in MyList is different from the number of selected items, which is what I want to work with. Otherwise I'd just be repeating the values of the entire CheckBoxList. –  Josh Earl Mar 3 '11 at 17:35
@JoshEarl: I don't see any check in the other samples where the non-selected items are excluded, nor in your example? –  Steven Jeuris Mar 3 '11 at 17:44
@Steven Sorry, the non-selected item issue was described in the body of my question, but I didn't include that part in my code for simplicity's sake. –  Josh Earl Mar 4 '11 at 12:58
@JoshEarl: no problem, but you do understand then, that the number of selected items is irrelevant? :) Count is always to total amount of items, selected and non-selected. –  Steven Jeuris Mar 4 '11 at 13:06
@Steven Well, it's relevant if you don't want to include the ", " after the last selected item. If you just loop through with the count and don't have a way of knowing when you reach the last selected item, you end up with a ", " after the last item, no? That was the problem I was trying to address with the silly string trim. –  Josh Earl Mar 4 '11 at 16:32

protected by syb0rgFeb 25 at 21:44

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.