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!
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());
}
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.
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.
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.
You can use
String csv = parts.Aggregate((s1,s2) => s1+","+s2);
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With