LINQ GroupBy 除了空值

Posted

技术标签:

【中文标题】LINQ GroupBy 除了空值【英文标题】:LINQ GroupBy except null values 【发布时间】:2021-06-04 01:11:29 【问题描述】:

我的目标是列出重复项,这就是我正在尝试的:

var duplicates = result
                 .GroupBy(x => x.col1)
                 .SelectMany(y => y.Count() > 1 ? y.Where(z => z.col2== decimal.Zero) : y)
                 .AsEnumerable()
                 .ToList();

但它已按col1 中的所有null 值分组。

示例输入

| col1   | col2   |
|--------|--------|
| 1/1/21 | 0.00   |
| 2/1/21 | 120.00 |
| 2/1/21 | 0.00   |
| 3/1/21 | 110.00 |
| null   | 140.00 |
| null   | 220.00 |
| 6/1/21 | 0.00   |
| 6/1/21 | 0.00   |
| 7/1/21 | 0.00   |
| null   | 0.00   |
|--------|--------|

期望的输出

| col1   | col2   |
|--------|--------|
| 1/1/21 | 0.00   |
| 2/1/21 | 120.00 |
| 3/1/21 | 110.00 |
| null   | 140.00 |
| null   | 220.00 |
| 6/1/21 | 0.00   |
| 7/1/21 | 0.00   |
| null   | 0.00   |
|--------|--------|

【问题讨论】:

可能是result.Where(x => x.col1 != null).GroupBy(x => x.col1)...? 能否与我们分享您的数据模型? 请看编辑 @MK88 如果您有像2/1/216/1/21 这样的副本,那么我们应该保留哪一个? GroupBy(col1),但 col1 中的 null 值除外。 【参考方案1】:

对于选择重复项,此查询应该有效:

var duplicates = result
   .GroupBy(x => x.col1)
   .Where(y => y.Count() > 1)
   .SelectMany()
   .ToList();

【讨论】:

【参考方案2】:

在您的GroupBy() 中,您需要处理col1 为空的情况并为组键分配唯一值。 Guid 可以很好地完成这项工作。试试这个:

var duplicates = result
                 .GroupBy(x => x.col1 == null ? Guid.NewGuid().ToString() : x.col1)
                 .Select(x => x.First())
                 .ToList();

【讨论】:

【参考方案3】:

样本数据

假设您的域模型与此类似:

class DomainModel

    public string Col1  get; 
    public double Col2  get; 

    public DomainModel(string col1, double col2)
    
        Col1 = col1;
        Col2 = col2;
    

出于测试目的,我将使用以下列表(填充您的示例输入):

var result = new List<DomainModel>

    new DomainModel("1/1/21", 0.00),
    new DomainModel("2/1/21", 120.00),
    new DomainModel("2/1/21", 0.00),
    new DomainModel("3/1/21", 110.00),
    new DomainModel(null, 140.00),
    new DomainModel(null, 220.00),
    new DomainModel("6/1/21", 120.00),
    new DomainModel("6/1/21", 0.00),
    new DomainModel("7/1/21", 0.00),
    new DomainModel(null, 0.00)
;

对相邻记录进行分组

如果我们可以依赖排序,那么我们可以将具有相同Col1 的相邻记录分组。为此,我们需要使用MoreLinq。

IEnumerable<IGrouping<string, DomainModel>> groupedResult = result.GroupAdjacent(c => c.Col1);

现在,如果我们使用以下命令打印出groupedResult

foreach (var group in groupedResult)

    Console.WriteLine(group.Key ?? "null");
    foreach (var model in group)
    
        Console.WriteLine($"\tmodel.Col2");
    

然后我们会看到以下输出:

1/1/21
        0
2/1/21
        120
        0
3/1/21
        110
null
        140
        220
6/1/21
        120
        0
7/1/21
        0
null
        0

过滤掉不必要的项目

如果我正确理解您的要求,那么您希望:

显示那些组中键为null的所有条目 显示具有单个条目的所有组 仅显示col2 不为0 且组中有更多条目的条目

这些可以翻译成以下查询:

var filteredResult = groupedResult.SelectMany(@group =>
    @group.Key == null
        ? @group //If col1 is null then return as is
        : @group.Count() == 1
            ? @group //If there is a single entry in a group then return as is
            : @group.Where(c => Math.Abs(c.Col2) > 0.01)); //If there are multiple entries then return those where col2 is not 0

如果我们执行这个查询,输出将是预期的:

foreach (DomainModel model in filteredResult)

    Console.WriteLine($"model.Col1 ?? "null" \t model.Col2");

1/1/21   0
2/1/21   120
3/1/21   110
null     140
null     220
6/1/21   120
7/1/21   0
null     0

【讨论】:

以上是关于LINQ GroupBy 除了空值的主要内容,如果未能解决你的问题,请参考以下文章

c# linq groupby是默认去掉重复行吗

linq GroupBy

Linq:GroupBy、Sum 和 Count

Linq 中按照多个值进行分组(GroupBy)

(转)Linq-GroupBy

LINQ技巧:如何通过多次调用GroupBy实现分组嵌套