65.9K
CodeProject 正在变化。 阅读更多。
Home

LINQ:介绍 Take Last 运算符

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2010 年 10 月 19 日

CPOL

2分钟阅读

viewsIcon

16047

LINQ:介绍 Take Last 运算符

前段时间,我需要检索满足某些条件的序列的最后几个项目,查看 Enumerable 类中可用的运算符,我注意到没有这样的运算符。StatCounter

实现此目的的唯一方法是反转序列,获取满足条件的项,然后反转结果序列。像这样

sequence.Reverse().TakeWhile(criteria).Reverse();

看起来很简单,对吧?首先,我们调用 Reverse 方法来生成一个新序列,该序列与原始序列具有相同的项目,但顺序相反,然后我们调用 TakeWhile 方法来获取满足条件的第一个项目,然后再次调用 Reverse 方法来恢复项目的原始顺序。

这种方法的问题在于 Reverse 方法在以相反的顺序迭代其项目之前会缓冲整个序列 - 上面的代码使用了两次。这意味着迭代原始序列中的所有项目并缓冲所有项目,迭代满足条件的 resulting 序列的第一个项目并缓冲所有项目,最后,迭代该结果以生成最终序列。

如果您正在计数,您会得出结论,原始序列中的所有项目将被迭代一次,而结果序列中的项目将被迭代三次。如果原始序列很大,这会占用大量内存和时间。

如果您使用在选择标准评估中使用原始序列中项目索引的变体(^),则存在另一个问题。当我们反转项目的顺序时,索引将被反转,并且谓词必须考虑到这一点,如果您不知道原始序列中项目的数量,则这可能是不可能的。

一定有更好的方法,这就是我实现 Take Last 运算符的原因

名称描述示例
TakeLast<TSource>(IEnumerable<TSource>)

从序列的末尾返回指定数量的连续元素。

int[] grades = { 59, 82, 70, 56, 92, 98, 85 };

var topThreeGrades = grades
                     .OrderBy(grade => grade)
                     .TakeLast(3);

Console.WriteLine("The top three grades are:");
foreach (int grade in topThreeGrades)
{
    Console.WriteLine(grade);
}
/*
This code produces the following output:

The top three grades are:
98
92
85
*/
TakeLastWhile<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>)

只要指定的条件为 true,就从序列的末尾返回元素。

string[] fruits =
    {
        "apple",
        "passionfruit",
        "banana",
        "mango",
        "orange",
        "blueberry",
        "grape",
        "strawberry"
    };

var query = fruits
            .TakeLastWhile(fruit => 
        string.Compare("orange", 
        fruit, true) != 0);

foreach (string fruit in query)
{
    Console.WriteLine(fruit);
}

/*
This code produces the following output:

blueberry
grape
strawberry
*/
TakeLastWhile<TSource>(IEnumerable<TSource>, Func<TSource, Int32, Boolean>)

只要指定的条件为 true,就从序列的末尾返回元素。

string[] fruits =
    {
        "apple",
        "passionfruit",
        "banana",
        "mango",
        "orange",
        "blueberry",
        "grape",
        "strawberry"
    };

var query = fruits
            .TakeLastWhile((fruit, index) => 
        fruit.Length >= index);

foreach (string fruit in query)
{
    Console.WriteLine(fruit);
}

/*
This code produces the following output:

strawberry
*/

您可以在我的 CodePlex 项目中找到这些(以及更多)运算符,用于 LINQ 实用程序和运算符:PauloMorgado.Linq

© . All rights reserved.