为了账号安全,请及时绑定邮箱和手机立即绑定

使用Linq获取集合的最后N个元素?

使用Linq获取集合的最后N个元素?

慕标5832272 2019-10-08 14:27:53
给定一个集合,有没有办法获取该集合的最后N个元素?如果框架中没有方法,那么编写扩展方法来执行此操作的最佳方法是什么?
查看完整描述

3 回答

?
德玛西亚99

TA贡献1770条经验 获得超3个赞

collection.Skip(Math.Max(0, collection.Count() - N));

这种方法保留了项目顺序,而无需依赖任何排序,并且在多个LINQ提供程序之间具有广泛的兼容性。


重要的是要注意不要以Skip负数呼叫。某些提供程序(例如,实体框架)在出现负参数时将产生ArgumentException。呼吁Math.Max巧妙地避免这种情况。


下面的类具有扩展方法的所有基本要素,这些要素是:静态类,静态方法和this关键字的使用。


public static class MiscExtensions

{

    // Ex: collection.TakeLast(5);

    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int N)

    {

        return source.Skip(Math.Max(0, source.Count() - N));

    }

}

关于性能的简要说明:


因为对的调用Count()可能导致某些数据结构的枚举,所以此方法具有导致两次通过数据的风险。对于大多数枚举对象而言,这并不是真正的问题。实际上,已经存在针对列表,数组甚至EF查询的优化,以评估Count()O(1)时间的操作。


但是,如果必须使用仅向前枚举,并且希望避免进行两次遍历,请考虑像Lasse V. Karlsen或Mark Byers这样描述的一次遍历算法。这两种方法都使用临时缓冲区在枚举时保存项目,一旦找到集合的末尾便会产生这些项目。


查看完整回答
反对 回复 2019-10-08
?
慕少森

TA贡献2019条经验 获得超9个赞

注意:我错过了您的问题标题“ 使用Linq”,因此我的答案实际上并未使用Linq。


如果要避免缓存整个集合的非惰性副本,则可以编写一个使用链接列表执行此操作的简单方法。


以下方法将在原始集合中找到的每个值添加到链接列表中,并将链接列表缩小为所需的项目数。由于它通过遍历整个集合始终将链接列表修剪为该项目数,因此它将仅保留原始集合中最多N个项目的副本。


它不需要您知道原始集合中的项目数,也不需要多次对其进行迭代。


用法:


IEnumerable<int> sequence = Enumerable.Range(1, 10000);

IEnumerable<int> last10 = sequence.TakeLast(10);

...

扩展方式:


public static class Extensions

{

    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> collection,

        int n)

    {

        if (collection == null)

            throw new ArgumentNullException("collection");

        if (n < 0)

            throw new ArgumentOutOfRangeException("n", "n must be 0 or greater");


        LinkedList<T> temp = new LinkedList<T>();


        foreach (var value in collection)

        {

            temp.AddLast(value);

            if (temp.Count > n)

                temp.RemoveFirst();

        }


        return temp;

    }

}


查看完整回答
反对 回复 2019-10-08
  • 3 回答
  • 0 关注
  • 797 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信