Linq GroupBy 查询中空组的默认值

Default values for empty groups in Linq GroupBy query

我有一组值,我想分组汇总。对于每个组,我想创建一个足够大的数组来包含最大组的值。当一个组包含的数量少于此最大数量时,我想为空键值插入默认值零。

数据集

Col1    Col2    Value
--------------------
A       X       10
A       Z       15
B       X       9
B       Y       12
B       Z       6

想要的结果

X, [10, 9]
Y, [0, 12]
Z, [15, 6]

请注意,数据集中 Col1 中的值 "A" 在 Col2 中没有 "Y" 的值。值 "A" 是外部系列中的第一组,因此它是缺少的第一个元素。

以下查询创建结果数据集,但不插入 Y 组的默认零值。

result = data.GroupBy(item => item.Col2)
             .Select(group => new
             {
                 name = group.Key,
                 data = group.Select(item => item.Value)
                             .ToArray()
             })

实际结果

X, [10, 9]
Y, [12]
Z, [15, 6]

我需要做什么才能插入一个零作为缺失的组值?

你可以这样做:-

int maxCount = 0;
var result = data.GroupBy(x => x.Col2)
             .OrderByDescending(x => x.Count())
             .Select(x => 
                {
                   if (maxCount == 0)
                       maxCount = x.Count();
                   var Value = x.Select(z => z.Value);
                   return new 
                   {
                      name = x.Key,
                      data = maxCount == x.Count() ? Value.ToArray() : 
                                 Value.Concat(new int[maxCount - Value.Count()]).ToArray()
                   };
                });

代码解释:-

因为你需要附加 default zeros 以防你在任何组中的项目较少,所以我存储了 maxCount(任何组都可以在变量 maxCount 中产生)为此我是按降序排列项目。接下来我将项目可以生产的最大数量存储在 maxCount 变量中。在投影时我只是检查组中的项目数是否不等于 maxCount 然后创建一个 integer array 大小 (maxCount - x.Count) 即最大计数减去当前项目数分组并将其附加到数组。

Working Fiddle.

它不会很漂亮,但你可以这样做:

var groups = data.GroupBy(d => d.Col2, d => d.Value)
                 .Select(g => new { g, count = g.Count() })
                 .ToList();
int maxG = groups.Max(p => p.count);
var paddedGroups = groups.Select(p => new {
                     name = p.g.Key,
                     data = p.g.Concat(Enumerable.Repeat(0, maxG - p.count)).ToArray() });

这是我的理解。

假设我们有这个

class Data
{
    public string Col1, Col2;
    public decimal Value;
}

Data[] source =
{
    new Data { Col1="A", Col2 = "X", Value = 10 },
    new Data { Col1="A", Col2 = "Z", Value = 15 },
    new Data { Col1="B", Col2 = "X", Value = 9 },
    new Data { Col1="B", Col2 = "Y", Value = 12 },
    new Data { Col1="B", Col2 = "Z", Value = 6 },
};

首先我们需要确定"fixed"部分

var columns = source.Select(e => e.Col1).Distinct().OrderBy(c => c).ToList();

然后我们可以使用正常的分组进行处理,但是在组内我们将左连接 columns 与组元素,这将使我们能够实现所需的行为

var result = source.GroupBy(e => e.Col2, (key, elements) => new
{
    Key = key,
    Elements = (from c in columns
             join e in elements on c equals e.Col1 into g
             from e in g.DefaultIfEmpty()
             select e != null ? e.Value : 0).ToList()
})
.OrderBy(e => e.Key)
.ToList();