By Osvaldo Orozco
This is the basic code that you can find when someone converts from an IEnumerable to a CSV string. This will be our starting point.
StringBuilder strBuild = new StringBuilder(1024);
foreach (var item in myList)
{
strBuild.AppendFormat("{0},", item.Key);
}
if (strBuild.Length > 0)
strBuild = strBuild.Remove(result.Length - 1, 1);
string result = strBuild.ToString();
Now, we are going to use the “Aggregate” LINQ function to create the CSV string.
First we need to add the namespace.
using System.Linq;
The Aggregate function has several overloaded methods.
The first method:
TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func);
We will change our code to:
StringBuilder strBuild = new StringBuilder(1024);
myList.Aggregate((acum, item) => acum + item);
if (strBuild.Length > 0)
strBuild = strBuild.Remove(strBuild.Length - 1, 1);
string result = strBuild.ToString();
But this will generate the following error.
Error 105: Operator '+' cannot be applied to operands of type 'MyComplexClass' and 'MyComplexClass'
This is because we have to override the “+” operator in order to use it with our class. So we can use the method:
TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func);
This method uses a seed as initial value as well as the return type of the method. And our code will look like:
string result = string.Empty;
result = = myList.Aggregate(result,
(acum, item) => acum + item.key + ",");
if (result.Length > 0)
result = result.Remove(result.Length - 1, 1);
The bad news is that we are concatenating strings. And concatenating string isn’t a good practice. So, we will use a StringBuilder.
StringBuilder strBuild = new StringBuilder(1024);
strBuild = myList.Aggregate(strBuild,
(acum, item) => acum.Append(item.key + ","));
if (strBuild.Length > 0)
strBuild = strBuild.Remove(strBuild.Length - 1, 1);
string result = strBuild.ToString();
Excellent, but we are getting a StringBuilder instead of a string. No problem, the “Aggregate” method has an overload that allows us to change the result.
TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAccumulate, TResult> resultSelector);
We will have this:
StringBuilder strBuild = new StringBuilder(1024);
string result = myList.Aggregate(strBuild,
(acum, item) => acum.Append(item.key + ","),
(acum) => acum.ToString());
if (result.Length > 0)
result = result.Remove(result.Length - 1, 1);
The seed is the initial value of the aggregate function, once we define the value it is used across the loop that accumulates the quantities. And the last “if” removes the last comma (,) of the string (if the IEnumerable is not empty). We can integrate this instruction as the “resultSelector”. And our code will be:
string result = myList.Aggregate(new StringBuilder(),
(acum, item) => acum.Append(item.key + ","),
(acum) => (acum.Length > 0) ? acum.Remove(acum.Length - 1,
1).ToString() : "");
Once we done all of the above, and walk through the “Aggregate” function provided by LINQ we can get a CSV string in an easy way with this:
string result = myList.Aggregate(new StringBuilder(),
(acum, item) => acum.Append(item.key + ","),
(acum) => (acum.Length > 0) ? acum.Remove(acum.Length - 1,
1).ToString() : "");
Is there an easy way to get a CSV from an IEnumerable? Yes, you can user this code:
string result = string.Join(",", myList.Select(l => l.Key).ToArray());