【问题标题】:Iterate through linq query results by day to check conditions按天迭代 linq 查询结果以检查条件
【发布时间】:2018-11-09 17:31:33
【问题描述】:

我有一个查询,它返回一个日期范围内的事件列表。

string EOOmessage = "";[enter image description here][2]
string eventText = "";
DateTime js = DateTime.Now;
DateTime je = DateTime.Now;
var itCompareDay = (from h in db.DailyGPSTables
                    where (h.EventDateTime >= startDate
                          && h.EventDateTime <= endDate)
                    select h).ToList();

我想检查每个事件的时间,以确保其顺序正确。例如 JE(Job End) 不能在 JS(Job Start) 之前。我尝试了很多方法,但这是我最新的方法。它会正确检查匹配的 JE 标签,但不考虑它所在的日期。

int rowNumber = -1;
foreach (DailyGPSTable e in itCompareDay)
{
    if (e.EventType == "JS")
    {
        js = e.EventDateTime.Value;
    }
    if (e.EventType == "JE")
    {
        je = e.EventDateTime.Value;
    }
    if (je < js)
    {
        EOOmessage = " On " + e.EventDateTime.Value.ToShortDateString() + " Job end is before Job Start " + eventText;
        errorList.Add(EOOmessage);
        errorListRow.Add(rowNumber);
    }
    rowNumber = rowNumber + 1;
}

有没有办法每天检查乱序事件,如果发现则报告它们,如果不去第二天?

【问题讨论】:

  • 其实因为属性是一个DateTime,所以应该在比较中包含日期,而不需要手动检查。
  • 你给出的当前代码示例有什么问题?
  • 它检查整个星期,而不仅仅是一天。
  • 所以第一次它在一个 js 之前找到一个 je,但在第三个它发现另一个 je abut 没有意识到第三个还有另一个 js。好像是用一号的js。
  • 我真的不明白你在问什么。您能否发布“期望的输出”,以便我们可视化您正在寻找什么样的结果?

标签: c# asp.net linq entity-framework-6


【解决方案1】:

根据我的成对扫描扩展方法,使用名为 GroupByWhile 的测试为真(或假)时按顺序扫描和分组的扩展方法:

public static class IEnumerableExt {
    // TKey combineFn((TKey Key, T Value) PrevKeyItem, T curItem):
    // PrevKeyItem.Key = Previous Key
    // PrevKeyItem.Value = Previous Item
    // curItem = Current Item
    // returns new Key
    public static IEnumerable<(TKey Key, T Value)> ScanPair<T, TKey>(this IEnumerable<T> src, TKey seedKey, Func<(TKey Key, T Value), T, TKey> combineFn) {
        using (var srce = src.GetEnumerator()) {
            if (srce.MoveNext()) {
                var prevkv = (seedKey, srce.Current);

                while (srce.MoveNext()) {
                    yield return prevkv;
                    prevkv = (combineFn(prevkv, srce.Current), srce.Current);
                }
                yield return prevkv;
            }
        }
    }

    // bool testFn(T prevItem, T curItem)
    // returns groups by sequential matching bool
    public static IEnumerable<IGrouping<int, T>> GroupByWhile<T>(this IEnumerable<T> src, Func<T, T, bool> testFn) =>
        src.ScanPair(1, (kvp, cur) => testFn(kvp.Value, cur) ? kvp.Key : kvp.Key + 1)
           .GroupBy(kvp => kvp.Key, kvp => kvp.Value);
}

您可以选择按EventDateTime 排序的有趣事件类型(JS/JE),然后按JS 后跟JE 分组并丢弃匹配对:

var itCompareDay = (from h in db.DailyGPSTables
                    where (h.EventDateTime >= startDate
                          && h.EventDateTime <= endDate)
                    orderby h.EventDateTime
                    select h).ToList();

var errEvents = itCompareDay
                    .Select((ev, rowNum) => new { ev.EventType, ev.EventDateTime, rowNum })
                    .Where(cd => cd.EventType == "JS" || cd.EventType == "JE")
                    .GroupByWhile((pd, cd) => pd.EventType == "JS" && cd.EventType == "JE" && pd.EventDateTime.Date == cd.EventDateTime.Date)
                    .Where(cdg => cdg.Count() != 2)
                    .SelectMany(cdg => cdg.Select(cd => new { cd.rowNum, ErrMsg = cd.EventType == "JE" ? "JE without preceding JS" : "JS without following JE" }));

请注意,rowNum 基于 0,但如果需要,您可以在第一个 Select 中添加 1。

【讨论】:

  • 哇,令人印象深刻!
  • 非常感谢,我无法通过简单地将代码复制并粘贴到新类中来实现扩展类
  • 必须在 static 类中实现扩展。我在答案中添加了包装器。
  • 仍然出现错误。我正在添加页面图片
  • @NetMage 我非常感谢您的回答并希望实施它。我现在必须离开办公室,但非常感谢帮助在 VS 上设置 GroupByWhile 扩展以运行..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-11
  • 1970-01-01
  • 2014-04-30
相关资源
最近更新 更多