How can I get the average of the elements of a generic list that meet a criteria?
10,227
I'd like to recreate a generic version of the excel function AVERAGEIF
Why don't you just use LINQ?
var average = collection.Where(x => x.Something)
.Average(x => x.SomeProperty);
Note that this will throw an exception if there are no matching elements. If you don't want that, you could use:
var average = collection.Where(x => x.Something)
.DefaultIfEmpty()
.Average(x => x.SomeProperty);
It's not clear why you would want to create a separate method for this.
Author by
slcott
Updated on July 26, 2022Comments
-
slcott almost 2 years
I'd like to recreate a generic version of the excel function AVERAGEIF. It is defined as the following:
Returns the average (arithmetic mean) of all the cells in a range that meet a given criteria
My problem is that I don't know how to define the type signature of the generic average function. The following is the almost working code that I have.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsTestApp { class Program { static void Main(string[] args) { var dl = new List<double>() { 10, 10, 0, 0 }; var bl = new List<bool>() { true, true, false, false }; Func<bool, bool> criteria = c => c == true; Console.Out.WriteLine(AVERAGEIF<double, bool>(dl, bl, criteria)); Console.In.Read(); } static T1 AVERAGEIF<T1, T2>(List<T1> average_range, List<T2> criteria_range, Func<T2, bool> applyCriteria) { var cl1 = new List<Container<T1>>(); foreach (var cl in average_range) { cl1.Add(new Container<T1>(cl)); } var cl2 = new List<Container<T2>>(); foreach (var cl in criteria_range) { cl2.Add(new Container<T2>(cl)); } List<Container<T1>> result = new List<Container<T1>>((from d in cl1 join b in cl2 on d.Id equals b.Id where applyCriteria(b.Value) select new Container<T1> { Value = d.Value, }).ToList<Container<T1>>()); var ret = result.Average<T1>(s => s.Value); // // return ret; return default(T1); } } class Container<T> { private static uint count = 0; public Container() : base() { count++; this.Id = count; } public Container(T t) : this() { this.Value = t; } public T Value { get; set; } public uint Id { get; private set; } } class ContainerList<T> : List<Container<T>> { List<Container<T>> m_list; public ContainerList() : base() { this.m_list = new List<Container<T>>(); } public ContainerList(List<T> l) : this() { foreach (var li in l) { this.m_list.Add(new Container<T>(li)); } } public ContainerList(List<Container<T>> l) : this() { this.m_list = l; } public T Average(Func<Container<T>, T> selector) { T ret = default(T); if (typeof(T) == typeof(double)) ret = (T)(object)(double)0.0; else if (typeof(T) == typeof(decimal)) ret = (T)(object)(decimal)0.0; else ret = default(T); return ret; } } }