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) 即最大计数减去当前项目数分组并将其附加到数组。
它不会很漂亮,但你可以这样做:
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();
我有一组值,我想分组汇总。对于每个组,我想创建一个足够大的数组来包含最大组的值。当一个组包含的数量少于此最大数量时,我想为空键值插入默认值零。
数据集
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) 即最大计数减去当前项目数分组并将其附加到数组。
它不会很漂亮,但你可以这样做:
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();