views:

1045

answers:

10

Given a list of strings, what is the best method for concatenating these strings into a comma separated list with no comma at the end. (VB.NET or C#) (Using either StringBuilder or String Concat.)

Dim strResult As String = ""
Dim lstItems As New List(Of String)
lstItems.Add("Hello")
lstItems.Add("World")
For Each strItem As String In lstItems
    If strResult.Length > 0 Then
        strResult = strResult & ", "
    End If
    strResult = strResult & strItem
Next
MessageBox.Show(strResult)
+25  A: 
Dim Result As String
Dim Items As New List(Of String)
Items.Add("Hello")
Items.Add("World")

Result = String.Join(",", Items.ToArray())
MessageBox.Show(Result)

If you're really concerned about empty strings, use this join function:

Function Join(ByVal delimiter As String, ByVal items As IEnumerable(Of String), Optional ByVal IgnoreEmptyEntries As Boolean = True) As String
    Dim delim As String = ""
    Dim result As New Text.StringBuilder("")

    For Each item As String In items
        If Not IgnoreEmptyEntries OrElse Not String.IsNullOrEmpty(item) Then
            result.Append(delim).Append(item)
            delim = delimiter
        End If
    Next
    Return result.ToString()
End Function
Joel Coehoorn
+1  A: 

There are several ways to do this, but they're basically variations on a theme.

Pseudocode:

For Each Item In Collection:
  Add Item To String
  If Not Last Item, Add Comma

A different way that I like a little better is something like this:

For Each Item In Collection:
  If Not First Item, Add Comma
  Add Item To String

Edit: The reason I like the second way of doing it is that each item stands on its own. Using the first approach, if you modified your logic later so that a subsequent item might not get added, you could end up with a stray comma at the end of the string unless you also made your test in the previous item more intelligent, which is dumb.

GalacticCowboy
+1  A: 

or you can do:

Separator = ""
For Each Item In Collection
  Add Separator + Item To String
  Separator = ", "

By setting the separator to an empty string in the first iteration you skip the first comma. One less if statement. This might or might not be more readable depending on what you're used to

Mendelt
+5  A: 

Like this:

lstItems.ToConcatenatedString(s => s, ", ")

If you want to ignore empty strings as in your example:

lstItems
    .Where(s => s.Length > 0)
    .ToConcatenatedString(s => s, ", ")

The most popular custom aggregate function in my toolbox. I use it every day:

public static class EnumerableExtensions
{

 /// <summary>
 /// Creates a string from the sequence by concatenating the result
 /// of the specified string selector function for each element.
 /// </summary>
 public static string ToConcatenatedString<T>(
  this IEnumerable<T> source,
  Func<T, string> stringSelector)
 {
  return EnumerableExtensions.ToConcatenatedString(source, stringSelector, String.Empty);
 }

 /// <summary>
 /// Creates a string from the sequence by concatenating the result
 /// of the specified string selector function for each element.
 /// </summary>
 /// <param name="separator">The string which separates each concatenated item.</param>
 public static string ToConcatenatedString<T>(
  this IEnumerable<T> source,
  Func<T, string> stringSelector,
  string separator)
 {
  var b = new StringBuilder();
  bool needsSeparator = false; // don't use for first item

  foreach (var item in source)
  {
   if (needsSeparator)
    b.Append(separator);

   b.Append(stringSelector(item));
   needsSeparator = true;
  }

  return b.ToString();
 }
}
Pete Montgomery
+1  A: 

Going on from the String.Join answer, to ignore null/empty strings (and if you are using .NET 3.5) you could use a bit of Linq. e.g.

Dim Result As String
Dim Items As New List(Of String)
Items.Add("Hello")
Items.Add("World")
Result = String.Join(",", Items.ToArray().Where(Function(i) Not String.IsNullOrEmpty(i))
MessageBox.Show(Result)
Paul Nearney
A: 

Would you believe there's a class in the .NET framework which provides this functionality?

public static string ListToCsv<T>(List<T> list)
        {
            CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection();

            list.ForEach(delegate(T item)
            {
                commaStr.Add(item.ToString());
            });


            return commaStr.ToString();
        }
edosoft
A: 
A: 
Dim strResult As String = ""
Dim separator = ","
Dim lstItems As New List(Of String)
lstItems.Add("Hello")
lstItems.Add("World")
For Each strItem As String In lstItems
     strResult = String.Concat(strResult, separator)
Next
strResult = strResult.TrimEnd(separator.ToCharArray())
MessageBox.Show(strResult)

the idea is to use String.TrimEnd() function

awaisj
+5  A: 

Does the solution have to use a StringBuilder or the Concat method?

If not, you could use the static String.Join method. For example (in C#):

string result = String.Join(",", items.ToArray());

See my very similar question for more details on this.

Daniel Fortunov
+2  A: 

If you don't have to use StringBuilder or Concat method you could also use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Configuration;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection();
            string[] itemList = { "Test1", "Test2", "Test3" };
            commaStr.AddRange(itemList);
            Console.WriteLine(commaStr.ToString()); //Outputs Test1,Test2,Test3
            Console.ReadLine();
        }
    }
}

This requires a reference to System.Configuration

Brad