从我的 LINQ 查询中计算百分比(按年)

Computing percentages (by year) from my LINQ query

我需要有关 Source 最近 5 年使用情况的统计数据。下面的 LINQ 查询允许我部分完成工作。

public class Source
{
    public int Id { get; set; }
    public string Label { get; set; }  
}

public class Suite
{
    public int Id { get; set; }
    public DateTime CreatedTime  { get; set; }
    public int SourceId { get; set; }
    public virtual Source Source { get; set; }
}

var limit = DateTime.Now.AddYears(-5).Year;
var data = _contextProvider.Context.Suites
            .GroupBy(x => new { x.CreatedTime.Year, x.SourceId })
            .Select(x => new
            {
                Year = x.Key.Year,
                SourceId = x.Key.SourceId,
                Count = x.Count()
            })
            .Where(x => x.Year >= limit)
            .OrderByDescending(x => x.Year).ToList();

此 LINQ 查询的结果如下所示:

现在我需要更进一步:我需要 SourceId 按年计算的使用百分比。

2018 年示例:

如您所见,2018 年共有 51 个元素(32+12+7)。这个总数允许我计算当年每个 SourceId 的百分比。像这样:

所以我的问题是如何从我的 data 对象中获取这些百分比?也许可以直接在我的基本 LINQ 查询中计算这些百分比?

你肯定很接近。我们可以通过将分组依据分为两步来获得您想要的统计数据。

这是所有的最终查询(我不保证它在 SQL 中的速度!:)

Suites
    .Where(x => x.Created.Year >= 2013)
    .GroupBy(x => x.Created.Year)
    .Select(x => new {
        Total = x.Count(),
        Year = x.Key,
        Sources = x.GroupBy(i => i.SourceId)
            .Select(i => new {
                ItemCount = i.Count(),
                Source = i.Key })
    }).SelectMany(x => x.Sources.Select(s => new {
        TotalItems = x.Total,
        x.Year,
        s.ItemCount,
        Percent = (double)s.ItemCount / x.Total,
        SourceId = s.Source}))
    .OrderBy(x => x.Year)
    .ThenBy(x => x.SourceId)

工作方式是我们首先按年份分组,因为那是最外层的分组。

这为我们提供了 2018 - [items]2017 - [items] 的两组(就我的数据而言)。

然后我们 select 得出我们的顶级信息,这将是完整的 Total 以及 Year。然而,对于单独的行,我们需要进行另一个分组。因此,当我们获取项目列表时,我们将按 SourceId 应用第二个分组,这将使我们获得给定年份下每个来源的行数。

这给了我们 2018 年:

2018

  • 2, [Items]

  • 3, [Items]

  • 6, [Items]

然后我们对这些组中的每一个进行 Select 并将它们展平到键和计数中,这给了我们以下内容:

2018

  • SourceId, Count

  • 2, 32

  • 3, 7

  • 6, 12

同样的结构也在 2017 年重复。

接下来我们要将其展平,以便我们对每年生成的每个 SourceId/Count 重复顶级分组数据。 SelectMany 非常适合这个,因为它需要可枚举的可枚举和 returns 一个单一的扁平化列表。

基本上,我们说对于每个年级组:Select 它下面的所有内容(3-6 个不同的 SourceId/Count 组)并将它们全部连接成一个列表。

当我们执行此连接步骤时,我们可以将 Select 应用于即将出现的行以获得最终计数。

这为我们提供了一组最终数据,如下所示:

Year, Total, Count, Percent, SourceId

2018, 51, 32, .627, 2

2018, 51, 7, .137, 3

2018, 51, 12, .235, 6

[Snip]

我在 LINQPad 中的结果如下所示: