Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make CSV from list of string in LINQ

Tags:

csv

linq

Hi I would like to take a list collection and generate a single csv line. So take this;

List<string> MakeStrings()
{
    List<string> results = new List<string>();
    results.add("Bob");
    results.add("Nancy");
    results.add("Joe");
    results.add("Jack");
    return results;       
}


string ContactStringsTogether(List<string> parts)
{
    StringBuilder sb = new StringBuilder();

    foreach (string part in parts)
    {
        if (sb.Length > 0)
            sb.Append(", ");

        sb.Append(part);
     }
     return sb.ToString();
}

This returns "Bob,Nancy,Joe,Jack"

Looking for help on the LINQ to do this in a single statement. Thanks!

like image 410
CmdrTallen Avatar asked May 03 '10 14:05

CmdrTallen


6 Answers

There are not any one liners to do this with LINQ. Note that you can use the Aggregate method to do this, but you will be using string concatenation instead of a StringBuilder. I would consider adding an extension method for this if it something you will be doing often:

    public static string ToCsv<T>(this IEnumerable<T> source)
    {
        if (source == null) throw new ArgumentNullException("source");
        return string.Join(",", source.Select(s => s.ToString()).ToArray());
    }
like image 57
Eric Hauser Avatar answered Oct 14 '22 00:10

Eric Hauser


var csv = string.Join(",", MakeStrings().ToArray());

I would personally recommend you using a real CSV parser instead of trying to do one liners that will break if your values contain a comma for example. You may read this article about rolling your own CSV parser.

like image 25
Darin Dimitrov Avatar answered Oct 14 '22 01:10

Darin Dimitrov


Using LINQ to build a CSV in a single statement may not be a great idea - particularly if the amount of data is signficant. Just because something is possible with LINQ does not mean it is automatically the best way to do so.

Building a CSV string is, by it's nature, an operation that requires concatenating and reallocating strings. You can use String.Join(), but it won't automatically escape characters like commas or double quotes. In fact, there are a number of non-trivial rules that are part of generating well-formed CSV files.

What you should really consider doing is using a proven library that generates correct CSV formatted data.

If you do choose to write your own implementation, be aware that techniques that involve concatenating many strings (like the Enumerable.Aggregate() offered as an example) may result in a lot of intermediate, throw-away string instances which will drag down performance. You will probably still want to use a StringBuilder in any real-world implementation.

Sometimes the clearest and simplest structure for code is still a loop.

like image 34
LBushkin Avatar answered Oct 14 '22 02:10

LBushkin


In .net 4.0,

string str = string.Join( ", ", MakeStrings());

Adding my answer here as a seperate one, so that it will be more clear for readers , not clear in my comments under Darin Dimitrov's answer.

like image 32
user_v Avatar answered Oct 14 '22 01:10

user_v


You can use

String csv = parts.Aggregate((s1,s2) => s1+","+s2);
like image 31
Jens Avatar answered Oct 14 '22 02:10

Jens


I pretty much just use this function to generate csv from linq. Its not perfect, but customizeable.

public string generateCsvFromLinqQueryable(IQueryable query,string delimiter,string replaceDelimiterInDataWith)
{
    PropertyInfo[] rowPropertyInfos = null;
    rowPropertyInfos = query.ElementType.GetProperties();

    string result = "";
    foreach (var myObject in query)
    {
        foreach (PropertyInfo info in rowPropertyInfos)
        {
            if (info.CanRead)
            {
                string tmp = Convert.ToString(info.GetValue(myObject, null));
                if (!String.IsNullOrEmpty(tmp))
                {
                    tmp.Replace(delimiter, replaceDelimiterInDataWith);
                }
                result +=  tmp + delimiter;
            }
        }
        result += "\r\n";
    }
    return result;
}

Harry

like image 1
Harry Avatar answered Oct 14 '22 00:10

Harry