как агрегировать запрос linq по разным группам - PullRequest
0 голосов
/ 13 июня 2019

Как вы выполняете несколько отдельных агрегаций для разных группировок в linq?

например, у меня есть таблица:

UNO     YOS Ranking Score
123456  1   42       17
645123  3   84       20

Я хочу выполнить набор агрегаций для этих данныхкак сгруппированные, так и не сгруппированные, например:

var grouped = table.GroupBy(x => x.score )
                    .Select(x => new 
                    {
                        Score = x.Key.ToString(),
                        OverallAverageRank = x.Average(y => y.Ranking),
                        Year1RankAvg = x.Where(y => y.YOS == 1).Average(y => y.Ranking),
                        Year2RankAvg = x.Where(y => y.YOS == 2).Average(y => y.Ranking)
                        //...etc
                    });

Я также хочу выполнить различные агрегации (стандартное отклонение) для одних и тех же срезов и целых данных.

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

1 Ответ

0 голосов
/ 20 июня 2019

Как и все программирование, когда у вас есть последовательность похожих предметов, используйте коллекцию. В этом случае я оставил его IEnumerable, но вы можете сделать его List или Dictionary на YOS, если хотите.

var ans = table.GroupBy(t => t.Score)
               .Select(tg => new {
                    Score = tg.Key,
                   OverallAverageRank = tg.Average(t => t.Ranking),
                   YearRankAvgs = tg.GroupBy(t => t.YOS).Select(tyg => new { YOS = tyg.Key, RankAvg = tyg.Average(t => t.Ranking) })
               });

Если вам нужно заполнить диапазон лет от 1 до макс (или другое число), вы можете изменить ответ:

var ans2 = ans.Select(soryr => new {
                    soryr.Score,
                    soryr.OverallAverageRank,
                    YearRankDict = soryr.YearRankAvgs.ToDictionary(yr => yr.YOS),
                    YearMax = soryr.YearRankAvgs.Max(yr => yr.YOS)
              })
              .Select(soryr => new {
                  Score = soryr.Score,
                  OverAverageRank = soryr.OverallAverageRank,
                  YearRankAvgs = Enumerable.Range(1, soryr.YearMax).Select(yos => soryr.YearRankDict.ContainsKey(yos) ? soryr.YearRankDict[yos] : new { YOS = yos, RankAvg = 0.0 }).ToList()
              });

Если вы предпочитаете, вы можете изменить исходный ans, чтобы он возвращал RankAvg как double? и поставить null вместо 0.0 при добавлении пропущенных лет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...