Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Fun with LINQ Aggregate

DZone's Guide to

Fun with LINQ Aggregate

· ·
Free Resource

Say we’ve got a CSV file:

private const string csv = 
@"1,2,3,4,5
6,7,8,9,10
11,12,13,14,15
16,17,18,19,20";

We want to parse it into nested List<int>, and then print out all the numbers on a single line. We might do it like this:

public void ParseCsvAndOutputAsString()
{
var data = new List<List<int>>();

foreach (var line in csv.Split('\n'))
{
var innerList = new List<int>();
foreach (var item in line.Split(','))
{
innerList.Add(int.Parse(item));
}
data.Add(innerList);
}

string output = "";
foreach (var innerList in data)
{
foreach (var item in innerList)
{
output = string.Format("{0} {1}", output, item);
}
}

Console.WriteLine(output);
}

Yes, I know I should use a StringBuilder and AddRange, but ignore that for the moment, I’m trying to make a point here.

Taking a collection of values and reducing them down to a single value is a very common task in programming. Here we’re doing it twice; first we’re taking a string, splitting it apart and then reducing it down to a single reference to a List<List<int>>; then we’re taking the may items of data and reducing them to a string.

This is so common in fact, that many programming languages have some kind of ‘reduce’ functionality built in. It’s especially common with functional languages. Did you know that C# also has a reduce function? It’s the Aggregate extension method. Here’s the same method written in two statements with it:

[Test]
public void ParseCsvAndOutputAsStringUsingAgregate()
{
var data = csv
.Split('\n')
.Aggregate(
new List<List<int>>(),
(list, line) => list.Append(line
.Split(',')
.Select(str => int.Parse(str))
.Aggregate(
new List<int>(),
(innerList, item) => innerList.Append(item))));

Console.WriteLine(data
.SelectMany(innerList => innerList)
.Aggregate("", (output, item) => string.Format("{0} {1}", output, item)));
}

Aggregate takes two parameters; the first sets up the initial value, in our case we create new instances of List<List<int>>, List<int> and an empty string, this is known as the ‘accumulator’; the second is the function that does the accumulating.

Aggregate works really well with fluent interfaces, where methods return their instance. I’ve added a fluent ‘Append’ extension method to List<int> to help me here:

public static List<T> Append<T>(this List<T> list, T item)
{
list.Add(item);
return list;
}

So any time you’ve got a collection of stuff that you want to ‘reduce’ to a single item, remember Aggregate.

 

Topics:

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}