- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我在 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/
我是一名优秀的程序员,十分优秀!