58
\$\begingroup\$

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?

\$\endgroup\$
2
  • \$\begingroup\$ Does this built-in do what you want? \$\endgroup\$ Mar 3, 2011 at 16:35
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Mar 3, 2011 at 21:25

4 Answers 4

73
\$\begingroup\$

Would this not suffice?

private string ConcatenateCheckBoxListItems()
{
    return string.Join(", ", from item in MyList select item.Value);
}
\$\endgroup\$
6
  • \$\begingroup\$ Cool, how didn't I know that one. :O :) \$\endgroup\$ Mar 3, 2011 at 16:42
  • 12
    \$\begingroup\$ @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. \$\endgroup\$
    – pdr
    Mar 3, 2011 at 16:46
  • \$\begingroup\$ I absolutely love this site. Yes, that's perfect, compact, elegant... I feel like more of a novice every day. :) \$\endgroup\$
    – Josh Earl
    Mar 3, 2011 at 17:30
  • 2
    \$\begingroup\$ @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 \$\endgroup\$
    – pdr
    Mar 3, 2011 at 18:23
  • 3
    \$\begingroup\$ Python? In my C#? In all seriousness, I didn't know you could do such wizardry in C#. Great answer. \$\endgroup\$ Mar 3, 2011 at 21:33
26
\$\begingroup\$

Why not string.Join()?

var result = string.Join(", ", MyList.Items.Select(i => i.Value));
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I very much prefer to do this inline over wrapping it in a method like in the accepted answer. \$\endgroup\$ Sep 18, 2015 at 23:59
5
\$\begingroup\$

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).

\$\endgroup\$
3
  • 3
    \$\begingroup\$ 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. \$\endgroup\$ Mar 4, 2011 at 13:52
  • \$\begingroup\$ 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 \$\endgroup\$
    – Jeff Fritz
    Mar 5, 2011 at 14:04
  • \$\begingroup\$ @StevenJeuris that thread gave me cancer \$\endgroup\$
    – DLeh
    Feb 27, 2014 at 20:21
1
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – Josh Earl
    Mar 3, 2011 at 17:35
  • \$\begingroup\$ @JoshEarl: I don't see any check in the other samples where the non-selected items are excluded, nor in your example? \$\endgroup\$ Mar 3, 2011 at 17:44
  • \$\begingroup\$ @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. \$\endgroup\$
    – Josh Earl
    Mar 4, 2011 at 12:58
  • \$\begingroup\$ @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. \$\endgroup\$ Mar 4, 2011 at 13:06
  • \$\begingroup\$ @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. \$\endgroup\$
    – Josh Earl
    Mar 4, 2011 at 16:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.