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?
4 Answers 4
Would this not suffice?
private string ConcatenateCheckBoxListItems()
{
return string.Join(", ", from item in MyList select item.Value);
}
-
\$\begingroup\$ Cool, how didn't I know that one. :O :) \$\endgroup\$Steven Jeuris– Steven Jeuris2011年03月03日 16:42:19 +00:00Commented 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– pdr2011年03月03日 16:46:10 +00:00Commented 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– Josh Earl2011年03月03日 17:30:55 +00:00Commented 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 quotesitem.Value.Contains(",") ? string.Format(@"""{0}""", item.Value) : item.Value
. Whatever you require \$\endgroup\$pdr– pdr2011年03月03日 18:23:57 +00:00Commented 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\$Humphrey Bogart– Humphrey Bogart2011年03月03日 21:33:48 +00:00Commented Mar 3, 2011 at 21:33
Why not string.Join()
?
var result = string.Join(", ", MyList.Items.Select(i => i.Value));
-
2\$\begingroup\$ I very much prefer to do this inline over wrapping it in a method like in the accepted answer. \$\endgroup\$Johan Larsson– Johan Larsson2015年09月18日 23:59:29 +00:00Commented Sep 18, 2015 at 23:59
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).
-
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\$Steven Jeuris– Steven Jeuris2011年03月04日 13:52:05 +00:00Commented 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– Jeff Fritz2011年03月05日 14:04:42 +00:00Commented Mar 5, 2011 at 14:04
-
\$\begingroup\$ @StevenJeuris that thread gave me cancer \$\endgroup\$DLeh– DLeh2014年02月27日 20:21:36 +00:00Commented Feb 27, 2014 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.
-
\$\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– Josh Earl2011年03月03日 17:35:01 +00:00Commented 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\$Steven Jeuris– Steven Jeuris2011年03月03日 17:44:34 +00:00Commented 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– Josh Earl2011年03月04日 12:58:53 +00:00Commented 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\$Steven Jeuris– Steven Jeuris2011年03月04日 13:06:37 +00:00Commented 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– Josh Earl2011年03月04日 16:32:56 +00:00Commented Mar 4, 2011 at 16:32
delimiter.ToCharArray()
in order to make maintenance just a tad bit easier. \$\endgroup\$