3 回答

TA貢獻(xiàn)1770條經(jīng)驗(yàn) 獲得超3個(gè)贊
collection.Skip(Math.Max(0, collection.Count() - N));
這種方法保留了項(xiàng)目順序,而無需依賴任何排序,并且在多個(gè)LINQ提供程序之間具有廣泛的兼容性。
重要的是要注意不要以Skip負(fù)數(shù)呼叫。某些提供程序(例如,實(shí)體框架)在出現(xiàn)負(fù)參數(shù)時(shí)將產(chǎn)生ArgumentException。呼吁Math.Max巧妙地避免這種情況。
下面的類具有擴(kuò)展方法的所有基本要素,這些要素是:靜態(tài)類,靜態(tài)方法和this關(guān)鍵字的使用。
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));
}
}
關(guān)于性能的簡(jiǎn)要說明:
因?yàn)閷?duì)的調(diào)用Count()可能導(dǎo)致某些數(shù)據(jù)結(jié)構(gòu)的枚舉,所以此方法具有導(dǎo)致兩次通過數(shù)據(jù)的風(fēng)險(xiǎn)。對(duì)于大多數(shù)枚舉對(duì)象而言,這并不是真正的問題。實(shí)際上,已經(jīng)存在針對(duì)列表,數(shù)組甚至EF查詢的優(yōu)化,以評(píng)估Count()O(1)時(shí)間的操作。
但是,如果必須使用僅向前枚舉,并且希望避免進(jìn)行兩次遍歷,請(qǐng)考慮像Lasse V. Karlsen或Mark Byers這樣描述的一次遍歷算法。這兩種方法都使用臨時(shí)緩沖區(qū)在枚舉時(shí)保存項(xiàng)目,一旦找到集合的末尾便會(huì)產(chǎn)生這些項(xiàng)目。

TA貢獻(xiàn)2019條經(jīng)驗(yàn) 獲得超9個(gè)贊
注意:我錯(cuò)過了您的問題標(biāo)題“ 使用Linq”,因此我的答案實(shí)際上并未使用Linq。
如果要避免緩存整個(gè)集合的非惰性副本,則可以編寫一個(gè)使用鏈接列表執(zhí)行此操作的簡(jiǎn)單方法。
以下方法將在原始集合中找到的每個(gè)值添加到鏈接列表中,并將鏈接列表縮小為所需的項(xiàng)目數(shù)。由于它通過遍歷整個(gè)集合始終將鏈接列表修剪為該項(xiàng)目數(shù),因此它將僅保留原始集合中最多N個(gè)項(xiàng)目的副本。
它不需要您知道原始集合中的項(xiàng)目數(shù),也不需要多次對(duì)其進(jìn)行迭代。
用法:
IEnumerable<int> sequence = Enumerable.Range(1, 10000);
IEnumerable<int> last10 = sequence.TakeLast(10);
...
擴(kuò)展方式:
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;
}
}
- 3 回答
- 0 關(guān)注
- 917 瀏覽
添加回答
舉報(bào)