Aggregate does not allow that in natural way.
You can carry previous element and do you final handling after Aggregate
. Also I think your best bet would be to write custom method that does that custom handling for last (and possibly first) element.
Some approximate code to special case last item with Aggregate
(does not handle most special case like empty/short list):
var firstLast = seq.Aggregate(
Tuple.Create(new StringBuilder(), default(string)),
(sum, cur) =>
{
if (sum.Item2 != null)
{
sum.Item1.Append(",");
sum.Item1.Append(sum.Item2);
}
return Tuple.Create(sum.Item1, cur);
});
firstLast.Item1.Append(SpecialProcessingForLast(sum.Item2));
return firstLast.Item1.ToString();
Aggregate
with special case for "last". Sample is ready to copy/paste to LinqPad/console app, uncomment "this" when making extension function. Main shows aggregating array with summing all but last element, last one is subtracted from result:
void Main()
{
Console.WriteLine(AggregateWithLast(new[] {1,1,1,-3}, 0, (s,c)=>s+c, (s,c)=>s-c));
Console.WriteLine(AggregateWithLast(new[] {1,1,1,+3}, 0, (s,c)=>s+c, (s,c)=>s-c));
}
public static TAccumulate AggregateWithLast<TSource, TAccumulate>(
/*this */ IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> funcAll,
Func<TAccumulate, TSource, TAccumulate> funcLast)
{
using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
{
return seed;
}
TSource last = sourceIterator.Current;
TAccumulate total = seed;
while (sourceIterator.MoveNext())
{
total = funcAll(total, last);
last = sourceIterator.Current;
}
return funcLast(total, last);
}
}
Note: if you need just String.Join
than one in .Net 4.0+ takes IEnumerable<T>
- so it will iterate sequence only once without need to ToList
/ToArray
.