Метод среднего расширения в Linq для значения по умолчанию - PullRequest
17 голосов
/ 29 марта 2011

Кто-нибудь знает, как я могу установить значение по умолчанию для среднего?У меня есть такая строка ...

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();

, которая выдает ошибку, потому что у меня еще нет оценок.Если у меня нет ни одного, я хочу, чтобы среднее значение по умолчанию равнялось 0. Я думал, что это должен быть метод расширения, где я мог бы указать, каким должно быть значение по умолчанию.

Ответы [ 3 ]

42 голосов
/ 29 марта 2011

Есть: DefaultIfEmpty.

Я не уверен, что ваши DbVersions и DbRatings и какая коллекция содержит ровно ноль предметов, но это идея:

var emptyCollection = new List<int>();
var average = emptyCollection.DefaultIfEmpty(0).Average();

Обновление: (повторяя то, что сказано в комментариях ниже, чтобы увеличить видимость)

Если вам нужно использовать DefaultIfEmpty для коллекции типов классов, помните, что вы можете изменить запрос LINQ на проект до агрегирования . Например:

class Item
{
    public int Value { get; set; }
}

var list = new List<Item>();
var avg = list.Average(item => item.Value);

Если вы не хотите / не можете создать значение по умолчанию Item с Value, равным 0, вы можете сначала проецировать на коллекцию int с, а , а затем предоставить значение по умолчанию :

var avg = list.Select(item => item.Value).DefaultIfEmpty(0).Average();
0 голосов
/ 29 марта 2011

Я попробовал некоторые из этих ответов, но в итоге получил больше исключений по той или иной причине. в итоге это сработало для меня. Я уверен, что производительность ужасна, но я вернусь позже.

var q1 = from v in db.DbVersions select new { VersionId = v.Id, AvgScore = v.DbRatings.Average(x => x.Score) as Nullable<double> };
var q2 = from p in dbPlugins select new { Plugin = p, AvgScore = q1.Where(x => p.DbVersions.Select(y => y.Id).Contains(x.VersionId)).Average(x => x.AvgScore) as Nullable<double> };
dbPlugins = q2.OrderByDescending(x => x.AvgScore).Select(x => x.Plugin).ToList();
0 голосов
/ 29 марта 2011

Я не думаю, что есть способ выбрать значение по умолчанию, но как насчет этого запроса

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();

По сути то же самое, что и ваш, но мы сначала спрашиваем, есть ли какие-либо рейтинги, прежде чем их усреднять.Если нет, мы возвращаем 0.

...