0

I would like to take the schema of a DataTable and import that into a comma separated string. So far I have the code shown below but I would really like this to be a one-liner solution if that is possible.

List<string> columns = new List<string>();
foreach (var column in MyDataTable.Columns)
    columns.Add(column.ToString());

string schema = string.Join(",", columns);

Is there a more concise way to do this?

Hooplator15
  • 1,540
  • 7
  • 31
  • 58
  • Don't forget to account for columns with names containing spaces or other special characters. – Sam Axe Sep 20 '16 at 19:05
  • 1
    "one liners" are not better. They usually sacrifice readability/maintainability. Your solution above looks readable and maintainable. Go with that. – Sam Axe Sep 20 '16 at 19:07
  • I mean, you can, but I agree with Sam. I also am not a huge fan of not including `{` and `}` around `foreach` statements, but oh well. `var schema = string.Join(",", MyDataTable.Columns.Cast().Select(r=>r.ColumnName));` is more concise if that's really what you want. – KSib Sep 20 '16 at 19:11
  • 1
    I agree with Sam Axe, one liners aren't always the way to go for maintainability. It's not like your code will run any quicker for having less lines! – matt_lethargic Sep 20 '16 at 19:21
  • `var cols = string.Join(",", dt.Columns.Cast().Select(c => c.ColumnName).ToArray());` not any faster and not all that much easier to read – Ňɏssa Pøngjǣrdenlarp Sep 20 '16 at 19:37
  • @KSib Your solution works for me. I agree that my original method was clear from a maintainability standpoint but at-least now I know how to do this on one line. (If for some reason I absolutely needed to) – Hooplator15 Sep 20 '16 at 19:45
  • @Plutonix, you haven't needed to use `.ToArray()` with `string.Join(...)` in several years. – Matthew Whited Sep 20 '16 at 21:02

2 Answers2

0

This previous post answers it nicely.

https://stackoverflow.com/a/28503521/1572750

public static string DataTableToCSV(this DataTable datatable, char seperator)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < datatable.Columns.Count; i++)
    {
        sb.Append(datatable.Columns[i]);
        if (i < datatable.Columns.Count - 1)
            sb.Append(seperator);
    }
    sb.AppendLine();
    foreach (DataRow dr in datatable.Rows)
    {
        for (int i = 0; i < datatable.Columns.Count; i++)
        {
            sb.Append(dr[i].ToString());

            if (i < datatable.Columns.Count - 1)
                sb.Append(seperator);
        }
        sb.AppendLine();
    }
    return sb.ToString();
}
Community
  • 1
  • 1
Bruce Burge
  • 144
  • 1
  • 15
0

Usage

MyDataTable.ToCsvFile("mycsv.csv")

... code ...

Note: this will be slightly slower than a few other examples but it is compliant with proper escaping for CSV as in RFC 4180

public static class CsvFileEx
{
    public static void ToCsvFile(this DataTable dt, string filename, bool includeHeaders = true)
    {
        dt.ToCsvLines(includeHeaders: includeHeaders).WriteAsLinesToFile(filename);
    }
    public static IEnumerable<string> ToCsvLines(this DataTable dt, string seperator = @"""", bool includeHeaders = true)
    {
        if (includeHeaders)
            yield return string.Join(seperator, dt.Columns
                                                  .Cast<DataColumn>()
                                                  .Select(dc => @"""" + dc.ColumnName.Replace(@"""", @"""""") + @""""));

        foreach (var row in dt.Rows.Cast<DataRow>())
            yield return string.Join(seperator, row.ItemArray
                                                   .Select(i => @"""" + (i ?? "").ToString().Replace(@"""", @"""""") + @""""));
    }
    public static void WriteAsLinesToFile(this IEnumerable<string> lines, string filename)
    {
        using (var writer = new StreamWriter(filename))
            foreach (var line in lines)
                writer.WriteLine(line);
    }
}
Matthew Whited
  • 22,160
  • 4
  • 52
  • 69