【发布时间】:2013-04-10 00:02:35
【问题描述】:
有没有办法使用 LINQ 来检查整数列表是否是“连续的” - 即 1、2、3、4、5 或 14、15、16、17、18?
【问题讨论】:
有没有办法使用 LINQ 来检查整数列表是否是“连续的” - 即 1、2、3、4、5 或 14、15、16、17、18?
【问题讨论】:
bool isSequential = Enumerable.Range(values.Min(), values.Count())
.SequenceEqual(values);
【讨论】:
您可以通过Enumerable.Zip:
bool sequential = values.Zip(values.Skip(1), (a,b) => (a+1) == b).All(x => x);
这通过获取每对值,并检查第二个是否比第一个大 1 并返回布尔值来工作。如果所有对都符合条件,则值是连续的。
鉴于这是一个整数的列表,您可以使用以下方法更有效地执行此操作:
bool sequential = values.Skip(1).Select((v,i) => v == (values[i]+1)).All(v => v);
这仅适用于可以通过索引访问的序列。请注意,我们使用values[i],而不是values[i-1],因为Skip 调用有效地移动了索引。
【讨论】:
Aggregate 来做到这一点,但前提是你让你的 lambda 有讨厌的副作用...... :(
另一种选择是使用Aggregate 仅迭代序列一次。
请注意,与 Reed Copsey 建议的 All 不同,Aggregate 在条件失败时不能在中间停止...
var s = new int[] {3,4,5,6}.ToList();
var isSequential = s.Aggregate
(
new {PrevValue = 0, isFirst = true, Success = true} ,
(acc, current) =>
new {
PrevValue = current,
isFirst = false,
Success = acc.Success && (acc.isFirst || (acc.PrevValue == current - 1))
}
)
.Success;
更高级的版本将是具有携带先前值的迭代器或将迭代器拆分为“First and the rest”的特殊代码,从而允许通过对任何可枚举的单次迭代来实现 Reed 的解决方案。
【讨论】:
ToList(),因为问题是关于列表的。我想要继续有趣和更高级的版本!
如果您已经知道列表中的数字是唯一,并且也是排序,那么最简单的顺序检查就是
lst[lst.Count - 1] - lst[0] == lst.Count - 1
假设列表中至少有 1 个元素。
【讨论】: