gpt4 book ai didi

c# - 如何在 C# 中使用 LINQ 查找乱序元素

转载 作者:太空宇宙 更新时间:2023-11-03 22:34:21 25 4
gpt4 key购买 nike

我在 c# 中有一个列表,它有两个日期时间字段:DatePaid 和 DateEntered。我想找到乱序的元素。这很容易,老派。按 DatePaid 对列表进行排序,然后在列表中执行 foreach,将 DateEntered 捕获到局部变量 (lastDateEntered) 中。每次通过循环,我们首先比较 DateEntered 和 lastDateEntered。如果 DateEntered 小于 lastDateEntered,则前一行将是乱序行。

| DatePaid | DateEntered | comments     |
|----------|-------------|--------------|
| 1/1/2019 | 1/1/2019 | |
| 2/1/2019 | 2/2/2019 | |
| 3/1/2019 | 3/1/2019 | |
| 4/1/2019 | 5/2/2019 | out of order |
| 5/1/2019 | 5/1/2019 | |

在 SQL 中(如果你不关心 SQL,请忽略这一段),很容易创建两个 CTE's (类似于子查询):一个按 DatePaid 排序,另一个按 DateEntered 排序。我们使用 Row_Number() 函数添加一个额外的字段,该字段已按 CTE 排序。然后我们加入每个 CTE 的行号,然后只选择一个 CTE 与另一个 CTE 的日期不相等的行。类似于 Oracle 12c - sql to find out of order rows尽管答案没有使用 CTE。我想我可以通过 linq 做一些类似的事情,但我不确定它会比 foreach 循环方法更容易。

有没有更好的 Linqish 方式?

最佳答案

使用基于 APL Scan 运算符的 LINQ 扩展(如 Aggregate,仅它返回中间结果),组合列表的 prev 和 cur 元素以获得新值,解决方案很简单。

一、扩展方法:

// TRes combineFn(T prevValue, T curValue)
public static IEnumerable<TRes> ScanByPairs<T, TRes>(this IEnumerable<T> src, Func<T, T, TRes> combineFn) {
using (var srce = src.GetEnumerator())
if (srce.MoveNext()) {
var prev = srce.Current;

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

现在您可以测试每个日期字段:

var ansdp = list.ScanByPairs((prev, cur) => new { OrderNotOkay = prev.DatePaid >= cur.DatePaid, prev })
.Where(op => op.OrderNotOkay)
.Select(op => op.prev)
.ToList();

var ansde = list.ScanByPairs((prev, cur) => new { OrderNotOkay = prev.DateEntered >= cur.DateEntered, prev })
.Where(op => op.OrderNotOkay)
.Select(op => op.prev)
.ToList();

(这给了我编写 WhereByPairs(及其许多同伴)的明显想法。)

如果不想使用扩展方法,可以使用 LINQ Zip 方法模拟同样的事情:

var ansde2 = list.Zip(list.Skip(1), (prev, cur) => new { OrderNotOkay = prev.DateEntered >= cur.DateEntered, prev })
.Where(op => op.OrderNotOkay)
.Select(op => op.prev)
.ToList();

当然,您可以将订单测试封装在扩展方法中:

public static class ListDateExt {
public static IEnumerable<T> OutOfOrder<T, TField>(this IEnumerable<T> src, Func<T,TField> selectorFn, Comparer<TField> cmp = null) {
cmp = cmp ?? Comparer<TField>.Default;
return src.ScanByPairs((prev, cur) => new { OrderNotOkay = cmp.Compare(selectorFn(prev), selectorFn(cur)) >= 0, prev })
.Where(op => op.OrderNotOkay)
.Select(op => op.prev);
}
}

然后您可以使用以下方法测试字段:

var ansdp = list.OutOfOrder(l => l.DatePaid).ToList();
var ansde = list.OutOfOrder(l => l.DateEntered).ToList();

关于c# - 如何在 C# 中使用 LINQ 查找乱序元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55872526/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com