Skip to content

Instantly share code, notes, and snippets.

@pmunin
Last active February 27, 2016 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmunin/0f4900c57a183b6f0083 to your computer and use it in GitHub Desktop.
Save pmunin/0f4900c57a183b6f0083 to your computer and use it in GitHub Desktop.
Aggregate several accumulators within one enumerator run
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// IEnumerable extension that allows to aggregate multiple accumulators within single enumerator run
/// Latest version is here: https://gist.github.com/pmunin/0f4900c57a183b6f0083
/// </summary>
internal static class AggregateManyExtensions
{
public static void Example()
{
var items = new[] { 9, 5, 2, 7, 3, 8, 3, 1 };
//Func<int, int, int> maxFunc = (item, seed) => Math.Max(item, seed);
//Func<int, int, int> sumFunc = (item, seed) => item + seed;
//Func<string, int, string> concatFunc = (seed, item) => string.Concat(item.ToString(), seed);
var x1 = items.Aggregate(0, (s, i) => Math.Max(s, i));
var x2 = items.Aggregate(0, (s, i) => s+i );
var x3 = items.Aggregate("", (s, i) => s + i.ToString());
var totals = items.AggregateMany()
.By((s, i) => Math.Max(s, i), 0)
.By((s, i) => s + i, 0)
.By((s, i) => s + i.ToString(), "")
.ToArray()
;
;
}
public class AggregateManyHost<TItem> : IEnumerable<object>
{
public IEnumerable<TItem> Items { get; set; }
public List<Aggregator<TItem>> Aggregators = new List<Aggregator<TItem>>();
bool aggregationDone = false;
public void Aggregate(bool reaggregate=true)
{
Aggregators.ForEach(a=>a.Reset());
if (aggregationDone&&(!reaggregate)) return;
Items.Aggregate(Aggregators, (aggs, i)=> {
aggs.ForEach(a => a.ProcessItem(i));
return aggs;
});
aggregationDone = true;
}
public IEnumerator<object> GetEnumerator()
{
Aggregate();
return Aggregators.Select(a=>a.GetResult()).Cast<object>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public abstract class Aggregator<TItem>
{
public abstract dynamic GetResult();
public abstract void ProcessItem(TItem item);
public abstract void Reset();
}
public class Aggregator<TItem, TAccumulate>:Aggregator<TItem>
{
public TAccumulate Result { get; set; }
public TAccumulate InitValue { get; set; }
public override dynamic GetResult()
{
return Result;
}
public Func<TAccumulate, TItem, TAccumulate> aggregateFunc { get; set; }
public override void ProcessItem(TItem item)
{
Result = aggregateFunc(Result, item);
}
public override void Reset()
{
Result = InitValue;
}
}
public static AggregateManyHost<TItem> AggregateMany<TItem>(this IEnumerable<TItem> items)
{
return new AggregateManyHost<TItem>() { Items = items };
}
public static AggregateManyHost<TItem> By<TItem, TAccumulator>(this AggregateManyHost<TItem> aggregateMany
, Func<TAccumulator, TItem, TAccumulator> aggregateFunc, TAccumulator seed = default(TAccumulator))
{
aggregateMany.Aggregators.Add(new Aggregator<TItem, TAccumulator>() { aggregateFunc = aggregateFunc, InitValue = seed });
return aggregateMany;
}
public static Func<TAccumulator> GetBy<TItem, TAccumulator>(this AggregateManyHost<TItem> aggregateMany
, Func<TAccumulator, TItem, TAccumulator> aggregateFunc, TAccumulator seed = default(TAccumulator))
{
aggregateMany.By(aggregateFunc, seed);
var aggregator = aggregateMany.Aggregators.Last() as Aggregator<TItem, TAccumulator>;
return () =>
{
aggregateMany.Aggregate(false);
return aggregator.Result;
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment