[ACCEPTED]-Average extension method in Linq for default value-average
There is: DefaultIfEmpty
.
I 'm not sure about what your 10 DbVersions
and DbRatings
are and which collection exactly has 9 zero items, but this is the idea:
var emptyCollection = new List<int>();
var average = emptyCollection.DefaultIfEmpty(0).Average();
Update: (repeating 8 what's said in the comments below to increase 7 visibility)
If you find yourself needing 6 to use DefaultIfEmpty
on a collection of class type, remember 5 that you can change the LINQ query to project 4 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 3 to/can not construct a default Item
with Value
equal 2 to 0, you can project to a collection of 1 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 5 AverageOrDefault, similar to FirstOrDefault. See 4 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 3 you'll need to create an AverageOrDefault 2 for double, int?, decimal, etc. They all 1 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(),
});
I don't think there's a way to select default, but 4 how about this query
dbPlugins = (from p in dbPlugins
select new {
Plugin = p, AvgScore =
p.DbVersions.Any(x => x.DbRatings) ?
p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) : 0 })
.OrderByDescending(x => x.AvgScore)
.Select(x => x.Plugin).ToList();
Essentially the same 3 as yours, but we first ask if there are 2 any ratings before averaging them. If not, we 1 return 0.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.