linq扩展方法从序列的末尾获取元素

Fab*_*ano 7 .net c# linq ienumerable linq-extensions

有可枚举的扩展方法

Take<TSource>(
    IEnumerable<TSource> source,
    int count
)
Run Code Online (Sandbox Code Playgroud)

count从一开始就采用第一个元素.

有没有办法从最后获取元素?甚至更好的方法从偏移到结束采取元素?

谢谢

Las*_*olt 13

finiteList.Reverse().Take(count).Reverse();
Run Code Online (Sandbox Code Playgroud)

要么

finiteList.Skip(finiteList.Count() - count)
Run Code Online (Sandbox Code Playgroud)

这样做有一些开销,所以自定义方法会更好.

更新:自定义方法

public static class EnumerableExtensions
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (count < 0) throw new ArgumentOutOfRangeException("count");

        if (count == 0) yield break;

        var queue = new Queue<T>(count);

        foreach (var t in source)
        {
            if (queue.Count == count) queue.Dequeue();

            queue.Enqueue(t);
        }

        foreach (var t in queue)
            yield return t;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:根据dtb的答案更改了代码:-)

评论熊:看看这个例子:

var lastFive = Enumerable.Range(1, 10).TakeLast(5);
var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way

Queue<int> q = (Queue<int>)lastFive2;
q.Dequeue();

//Is lastFive2 still last five? no...
Run Code Online (Sandbox Code Playgroud)

您可能会更改值,lastFive2因此该方法可能不安全或至少不是功能方式.

忍受忍受:

我对安全的意义是这样的:

var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way

//some = Some method which you don't control - it could be from another assembly which represents a crazy plugin etc.
some(lastFive2);
//Now what?
Run Code Online (Sandbox Code Playgroud)

在这些情况下,您必须制作副本才能确定.但在大多数情况下你的方式会很好 - 比这更有效率所以+1 :)

一个想法是使用只有内部Enqueue等的队列.