Anyone know how I can set a default value for an average? I have a line like this...
dbPlugins = (from p in dbPlugins select new { Plugin = p, AvgScore = p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) }) .OrderByDescending(x => x.AvgScore) .Select(x => x.Plugin).ToList();
which throws an error becase I have no ratings yet. If I have none I want the average to default to 0. I was thinking this should be an extension method where I could specify what the default value should be.
In LINQ, you can find the average of the given sequence by using the Average method. This method returns the average of the elements present in the given sequence or collection. It returns nullable, non-nullable decimal, double, floats, int, etc. values.
Extension Methods are a new feature in C# 3.0, and they're simply user-made pre-defined functions. An Extension Method enables us to add methods to existing types without creating a new derived type, recompiling, or modifying the original types.
There is: DefaultIfEmpty
.
I 'm not sure about what your DbVersions
and DbRatings
are and which collection exactly has zero items, but this is the idea:
var emptyCollection = new List<int>(); var average = emptyCollection.DefaultIfEmpty(0).Average();
Update: (repeating what's said in the comments below to increase visibility)
If you find yourself needing to use DefaultIfEmpty
on a collection of class type, remember that you can change the LINQ query to project before aggregating. For example:
class Item { public int Value { get; set; } } var list = new List<Item>(); var avg = list.Average(item => item.Value);
If you don't want to/can not construct a default Item
with Value
equal to 0, you can project to a collection of int
s first and then supply a default:
var avg = list.Select(item => item.Value).DefaultIfEmpty(0).Average();
My advice would to create a reusable solution instead of a solution for this problem only.
Make an extension method AverageOrDefault, similar to FirstOrDefault. See extension methods demystified
public static class MyEnumerableExtensions { public static double AverageOrDefault(this IEnumerable<int> source) { // TODO: decide what to do if source equals null: exception or return default? if (source.Any()) return source.Average(); else return default(int); } }
There are 9 overloads of Enumerable.Average, so you'll need to create an AverageOrDefault for double, int?, decimal, etc. They all look similar.
Usage:
// Get the average order total or default per customer var averageOrderTotalPerCustomer = myDbContext.Customers .GroupJoin(myDbContext.Orders, customer => customer.Id, order => order.CustomerId, (customer, ordersOfThisCustomer) => new { Id = customer.Id, Name = customer.Name, AverageOrder = ordersOfThisCustomer.AverageOrDefault(), });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With