Linq 高级分组 + 计数到新模型

Posted

技术标签:

【中文标题】Linq 高级分组 + 计数到新模型【英文标题】:Linq Advanced Grouping + Count to new model 【发布时间】:2020-11-16 18:05:54 【问题描述】:

我正在尝试编写一个 linq 操作来获取具有分组模型信息的唯一日期列表

到目前为止,我已经构建了这个查询,但我一直无法获得正确的输出

var result = LogModels
 .Where(x => x.LogType.ToLower() == "error" && 
             x.LogLevel.ToLower() == "error")
 .GroupBy(inf => inf.ErrorCode)
 .Select(inf => Tuple.Create(inf.Key, inf.Count()))
 .ToList();

我想要得到的输出是这样的

占位符:26/07/2020 [第 1 项] ->>> 错误 = A00.1 ->>> 消息 = 设置未正确执行 ->>> 错误数量 = 2 [第 2 项] ->>> 错误 = A05.1 ->>> 消息 = 安装程序已正确安装 ->>> 错误数量 = 1

占位符:27/07/2020 [第 1 项] ->>> 错误 = A00.1 ->>> 消息 = 设置未正确执行 ->>> 错误数量 = 1 [第 2 项] ->>> 错误 = A05.1 ->>> 消息 = 安装程序已正确安装 ->>> 错误数量 = 1

我的模型类

    public class LogModels

    public DateTime Date  get; set; 
    public string ErrorCode  get; set; 
    public string Message  get; set; 
    public string LogLevel  get; set; 
    public string LogType  get; set; 

希望任何人都可以帮助我。 问候我

【问题讨论】:

为什么不按Date 而不是ErrorCode 分组? .GroupBy(inf => inf.Date.Date) 我只想获取一个包含唯一模型的日期列表,其中显示错误发生的总数并将错误消息添加到其中。 【参考方案1】:

我只想获取一个包含唯一模型的日期列表,其中显示错误发生的总数并将错误消息添加到其中

因此,您希望创建具有相同日期的错误 LogModel 组,并从每个组中计算具有相同 ErrorCode 的错误数。

显然每个错误代码都只有一个消息。没有相同 ErrorCode 和不同消息的组合:所以不是:[ErrorCode X, Message 1] [ErrorCode X, Message 2]

好吧,让我们使用overload of GroupBy that has a parameter ResultSelector: 我们会将您的 LogModel 分组到具有相同日期的组中,并使用相同的错误代码对它们进行分组:

var result = LogModels.Where(...).GroupBy(
    
    // parameter keySelector: make groups with same Date:
    logModel => logModel.Date,

    // parameter resultSelector: from every found date, and all LogModels with this date make 
    // make one new object:
    (date, logModelsWithThisDate) => new
    
        PlaceHolder = date,

        // sub-group by ErrorCode:
        LogModels = logModelsWithThisDate.GroupBy(logModel => logModel.ErrorCode,

            // parameter resultSelector: from the errorCode,
            // and all logModels with this errorCode make one new:
            (errorCode, logModelsWithThisErrorCode) => new
            
                Error = errorCode,

                // you know that all logModels with this ErrorCode have the same Message,
                // so you can take any LogModel to get the Message:
                Message = logModelsWithThisErrorCode
                    .Select(logModel => logModel.Message)
                    .FirstOrDefault(),

                ErrorQty = logModelsWithThisErrorCode.Count(),
            ),
    );

或者,您可以对 ErrorCode 和 Message 进行分组

.GroupBy(logModel => new

    ErrorCode = logModel.ErrorCode,
    Message = logModel.Message,
,
// ResultSelector:
(error, logModelsWithThisError) => new

    ErrorCode = error.ErrorCode,
    Message = error.Message,
    ErrorQty = logModelsWithThisError.Count(),
)

虽然这样可行,而且结果选择器看起来更好,但效率较低,因为对于每个键,它必须同时检查 ErrorCode 和 Message,而您确实知道如果 x.ErrorCode 等于 y.ErrorCode,那么x.Message 将等于 y.Message,那么为什么要检查呢?

【讨论】:

感谢您的帮助。没有你就不会找到它!有什么关于 Linq 的好书推荐吗? 考虑The Standard Linq Operators。要了解 LINQ 背后的工作原理:Extension methods demystified。如果您忘记了适合您需要的方法,这也有助于您创建新的 LINQ 方法。有时,foreach (...)yield return 比一个大而复杂的 LINQ 语句更容易理解

以上是关于Linq 高级分组 + 计数到新模型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 dplyr 将跨因子级别的分组计数保存到新变量中?

Linq 按连接表中的项目计数分组

Linq to SQL - 分组和计数

LINQ C# 中的条件计数分组依据

如何使用linq计数和分组

具有多重嵌套表的分组方式和计数作为 LINQ 查询