views:

246

answers:

6

Suppose I have a collection of strings:

"foo"
"bar"
"xyz"

And I would like to generate a comma separated values from the list into something like:

"foo, bar, xyz"

Notice the lack of ", " at the end.

I am aware that there are dozens of ways to generate this:

  • use for-loop and string.Format() or StringBuilder.
  • use integer counter and remove the ending ", " if the value > 0
  • don't put ", " on the first run
  • etc.

Sample code of what I have right now:

if (strs.Count() > 0)
{
  var sb = new StringBuilder();
  foreach (var str in strs)
    sb.AppendFormat("{0}, ", str);
  return sb.Remove(0, 2).ToString();
}

What is the best code that is highly reusable for the above scenario, and why?

+25  A: 

You want to use the string.Join method, which exists in the BCL for this purpose.

Example:

var myArray = new string[] { "one", "two", "three" };
var output = string.Join(", ", myArray);

Or if you're using .NET 3.5, you can do this with any IEnumerable<string> as such:

var output = string.Join(", ", myEnumerable.ToArray());

(Note that this doesn't give the best performance as it requires, although it is clearly still 'O(n)', and should be suitable for almost all cases).

Now, if your enumerable is not of type string (generically an IEnumerable<T>), you can just use the Select method to convert the result into a string, e.g.

var output = string.Join(", ", myEnumerable.Select(e => e.ToString()).ToArray());


I'm not sure if you're dealing with values that may potentially contains commas in themselves, but this can be worked around by enclosing them in quotes (") and escaping the quotes, similarly to the CSV format.

var output = string.Join(", ", items.Select(x => x.Contains(",") ?
    "\"" + x.Replace("\"", "\"\"") + "\"" : x);

Of course, splitting them back up again is a slightly triciker task, which requires a bit of regex.

Noldorin
Hmm... I didn't know this function exists (makes my question look bad).
Adrian Godong
@Adrian: No worries. If you're not from a .NET background, discovering new things in the framework isn't is always straightforward - it's an ongoign process of building up familiarity.
Noldorin
That's the problem, I've been doing .NET since the first version. Duh.
Adrian Godong
Heh, well we're all still learning new features of the BCL. I think the fact that your question has been voted up shows it wasn't a stupid question. :)
Noldorin
You'll want to be careful here. If any of the strings contains a comma, it will throw the csv off.
yodaj007
@yodaj007: Indeed, he'll need to use a slightly more complicated method for that, and splitting would need to be done using a regex or such. It's not specified in the question however, so I'm not sure if it's necessary.
Noldorin
@Noldorin No, that won't be necessary. Version 1 of your answer is good enough.
Adrian Godong
@Adrian: I suspected so. It's there anyway however, in case it might help others. :)
Noldorin
A: 

Use String.Join

Eric Petroelje
+3  A: 
string finalstr = String.Join(",", strs);
Mr. Smith
A: 

If you have an array of strings, go with Noldorin's solution.

But if it's some other collection type, I might do this:

if (strs.Count() > 0)
{
  var sb = new StringBuilder();
  foreach (var str in strs)
    sb.AppendFormat("{0} {1}", (0 == sb.Length ? "" : ","), str);
  return sb.ToString();
}
John MacIntyre
+4  A: 
Joel Coehoorn
Yes, that's apparently the more common scenario. IEnumerable<string> than string[].
Adrian Godong
+1 The 'result.Append(d).Append(s)' is interesting ... never even thought of that. It'd be kind of neat to see how many different ways this simple task is currently being done.
John MacIntyre
The really cool thing is the jitter will normally optimize the extra assignments away, so the code does _exactly_ what you want it o.
Joel Coehoorn
+3  A: 

String.Join is the right answer, but in the case of an IEnumerable, Linq is often shorter than a for loop:

someStringCollection.Aggregate((first, second) => first + ", " + second);
GlennS
Nice usage of LINQ!
Adrian Godong