Linq:根据条件计算两个条目之间的差异(前瞻)

Posted

技术标签:

【中文标题】Linq:根据条件计算两个条目之间的差异(前瞻)【英文标题】:Linq: Calculate difference between two entries based on condition (lookahead) 【发布时间】:2022-01-08 20:35:31 【问题描述】:

数据库包含带有设备特定代码的错误日志条目。如果代码为非 0 则错误为活动,为 0 则为无效。一次只能激活一个错误,因此存在设备“出错”和“未出错”的时间范围;但是可以同时发布许多其他错误代码(这与设备错误状态无关,此处感兴趣)。

我想计算设备“出错”的次数。不幸的是,我们不能假设错误总是交替出现(101, 0, 200, 0, 302, 0),但可能更混乱(3, 101, 0, 20, 202, 10, 0, 0, 102, ...)。在这里,每次的错误时间都是从第一个非零错误码开始计算到第一个0,所以第一个非零出现到第一个零出现之间的时间差,然后从第一个非零开始等等。

换句话说:

timeStamp    code
100          101
200          0
300          500
350          501
400          0

--> Total Error Time = 200 ((200 - 100) + (400 - 300))

在循环中,这将是这样的任务:

totalErrorTime = 0;
previousError = errors.FirstOrDefault(x => x.code != 0);

errors.forEach(error => 
    if (previousError.code == 0 && error.code != 0)
        // Set first encountered non zero error code
        previousError = error;
    if (error.code == 0) 
        // Encountered 0 error code, calculate difference
        totalErrorTime += error.timeStamp - previousError.timeStamp;
        // Set previous error to this error for lookahead
        previousError = error;
    

但我想知道如何在 Linq 中执行类似的操作。到目前为止,我在想这样的事情:

var skippedErrors = errors;

result = errors
      .Zip(skippedErrors.Skip(1).SkipWhile(x => x.code != 0), (a, b) => new
           
                 errorTime = b.timeStamp - a.timeStamp
           )
      .Select(x => new ErrorTimeResult(x.Sum(y => y.errorTime))));

但是,我认为SkipWhile() 部分并不安全。

如何在 Linq 中进行这些“前瞻”?我认为Zip() 是正确的方法,但我怎样才能确保只计算每个“错误阶段”一次?谢谢。

【问题讨论】:

在数据库级别执行此操作不是更简单、更高效吗? 【参考方案1】:

我认为您需要对值进行规范化,然后执行子查询,然后执行 group by 以获取数据,如下所示:

using System;
using System.Linq;
using Newtonsoft.Json;
                    
public class Program

    public static void Main()
    
            var l = (new[]
            
                new TimeStamp = 100, Code = 0 ,
                new TimeStamp = 200, Code = 2 ,
                new TimeStamp = 300, Code = 3 ,
                new TimeStamp = 400, Code = 0 ,
                new TimeStamp = 520, Code = 34 ,
                new TimeStamp = 50, Code = 2 ,
                new TimeStamp = 500, Code = 0 
            ).ToList();

            l = l.OrderBy(a => a.TimeStamp).ToList();
            var err = l.OrderBy(a => a.TimeStamp).Select(a => new
            
                code = a.Code == 0 ? 0 : 1,
                a.TimeStamp,
                last = l.FirstOrDefault(b => b.TimeStamp > a.TimeStamp)?.Code == 0 ? 0 : 1,
                lastTimestamp = l.FirstOrDefault(b => b.TimeStamp > a.TimeStamp)?.TimeStamp
            ).GroupBy(a => new a.code, a.last,
                a => new a.TimeStamp, a.lastTimestamp , 
                (key, g) => new  
                        key.code, key.last, timestamp = g.Max(b => b.TimeStamp),
                        lastTimestamp = g.Min(b => b.lastTimestamp)
                
                ).OrderBy(a => a.timestamp);


        
            Console.Write(JsonConvert.SerializeObject(err,Formatting.Indented));
    

在这里测试:https://dotnetfiddle.net/

【讨论】:

感谢您的回答。我正在尝试理解它,并会在我实施后报告。

以上是关于Linq:根据条件计算两个条目之间的差异(前瞻)的主要内容,如果未能解决你的问题,请参考以下文章

根据另一列计算两个标记之间的差异

使用 Linq 根据条件过滤对象列表

如何计算两个日期之间的差异?

在 Swift 中计算两个日期之间的差异

计算两个不相邻行之间的差异

TSQL计算最旧和最新行之间的差异