Iterate through linq query results by day to check conditions

馋奶兔 提交于 2019-12-10 12:14:41

问题


I have a query that returns a list of events in a date range.

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();

I want to check the time for each event to make sure its in the proper sequence. For example JE(Job End) cannot be before JS(Job Start). I have tried many ways but this is my latest. It checks for a matching JE tag correctly but it doesn't account for which day it is in.

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;
}

Is there a way to check each day for out of sequence events and if found report them if not go to the next day?


回答1:


Using an extension method that scans sequentially and groups while a test is true (or false) named GroupByWhile based on my extension method for scanning by pairs:

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);
}

You can select out the interesting event types (JS/JE) ordered by EventDateTime and then group by JS followed by JE and throw out matching pairs:

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" }));

Note that rowNum is 0 based but you could add 1 in the first Select if desired.



来源:https://stackoverflow.com/questions/53230672/iterate-through-linq-query-results-by-day-to-check-conditions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!