我的问题与此类似:Find Consecutive Items in List using Linq。除了,我想获得最后一个没有间隙的连续项目。例如:
2, 4, 7, 8
输出
7,8
另一个例子:
4,5,8,10,11,12
输出
10,11,12
怎么可能呢?
我的问题与此类似:Find Consecutive Items in List using Linq。除了,我想获得最后一个没有间隙的连续项目。例如:
2, 4, 7, 8
输出
7,8
另一个例子:
4,5,8,10,11,12
输出
10,11,12
怎么可能呢?
我假设您想要最后一个具有多个成员的连续序列......所以从序列
{4, 5, 8, 10, 11, 12, 15}
你期待的顺序:
{10, 11, 12}
如果最后一个序列只允许有一个成员,我已经指出要删除的行,给出一个序列
{15}
这是linq:
new[] {4, 5, 8, 10, 11, 12, 15}
.Select((n,i) => new {n, i})
.GroupBy(x => x.n - x.i) //this line will group consecutive nums in the seq
.Where(g => g.Count() > 1) //remove this line if the seq {15} is expected
.Select(x => x.Select(xx => xx.n))
.LastOrDefault()
这里有一个隐藏的假设,即序列的数字是按升序排列的。如果不是这种情况,则有必要注册 microsoft 扩展方法的权限,以查找序列中的连续项目。让我知道是否是这种情况。
在这种情况下,这很有效,并且可能比 LINQ 更容易和更有效:
var list = new[] { 2, 4, 7, 8 };
List<int> lastConsecutive = new List<int>();
for (int i = list.Length - 1; i > 0; i--)
{
lastConsecutive.Add(list[i]);
if (list[i] - 1 != list[i - 1])
break;
if(i==1 && list[i] - 1 == list[i - 1]) // needed since we're iterating just until 1
lastConsecutive.Add(list[0]);
}
lastConsecutive.Reverse();
我意识到这既晚又罗嗦,但这可能是这里仍然使用 LINQ 的最快方法。
测试清单:
var list1 = new List<int> {2,4,7,8};
var list2 = new List<int> {4,5,8,10,11,12,15};
方法:
public List<int> LastConsecutive(List<int> list)
{
var rev = list.AsEnumerable().Reverse();
var res = rev.Zip(rev.Skip(1), (l, r) => new { left = l, right = r, diff = (l - r) })
.SkipWhile(x => x.diff != 1)
.TakeWhile(x => x.diff == 1);
return res.Take(1).Select(x => x.left)
.Concat(res.Select(x => x.right))
.Reverse().ToList();
}
这个从后到前并成对检查元素,仅从它们开始连续(the SkipWhile
)直到它们结束连续(the TakeWhile
)获取元素。
然后它会做一些工作来提取相关的成对数字(“原始”列表中的左侧数字,然后是所有正确的数字),并将其反转回来。与命令式版本的效率相似,但在我看来,由于 LINQ 更易于阅读。