Last active
February 27, 2016 01:28
-
-
Save pmunin/0f4900c57a183b6f0083 to your computer and use it in GitHub Desktop.
Aggregate several accumulators within one enumerator run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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