使用LINQ如何获取序列中除最后一个元素以外的所有元素?

172

假设我有一个序列。

IEnumerable<int> sequence = GetSequenceFromExpensiveSource();
// sequence now contains: 0,1,2,3,...,999999,1000000

获取这个序列是不廉价的,而且是动态生成的,我只想遍历一次。

我想要获取0-999999(即除最后一个元素外的所有元素)。

我知道我可以像这样做:

sequence.Take(sequence.Count() - 1);

但这会导致对大序列进行两次枚举。

是否有 LINQ 构造可让我执行:

sequence.TakeAllButTheLastElement();

3
你必须在O(2n)时间复杂度和O(count)空间复杂度算法之间做出选择,后者还需要在内部数组中移动项目。 - Dykam
1
Dario,请你为那些不太了解大O符号的人解释一下,好吗? - alexn
请参考此重复问题:https://dev59.com/U2855IYBdhLWcg3wvnKE - stakx - no longer contributing
1
最终我通过将集合转换为List并调用sequenceList.RemoveAt(sequence.Count - 1);来进行缓存。在我的情况下,这是可以接受的,因为在所有LINQ操作之后,我必须将其转换为数组或IReadOnlyCollection。我想知道你的使用情况,在那里你甚至不考虑缓存?正如我所看到的,即使是批准的答案也会进行一些缓存,因此在我看来,简单地转换为List更容易和更短。 - Pavels Ahmadulins
22个回答

-3
一个简单的方法是将其转换为队列,然后出队,直到只剩下您想要跳过的项目数量。
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int n)
{
    var queue = new Queue<T>(source);

    while (queue.Count() > n)
    {
        yield return queue.Dequeue();
    }
}

Take用于获取已知数量的项目。对于足够大的可枚举队列来说,这是非常糟糕的。 - Sinatr

-6

我可能会这样做:

sequence.Where(x => x != sequence.LastOrDefault())

这是一次迭代,每次都会检查它是否是最后一次。


5
不这样做的两个原因:1)LastOrDefault()需要遍历整个序列,并且对序列中的每个元素都进行调用(在.Where()中)。2)如果序列是[1,2,1,2,1,2],并且您使用了该技术,则会剩下[1,1,1]。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接