lambda 参数如何在 TakeWhile 中映射

本文关键字:TakeWhile 映射 参数 lambda | 更新日期: 2023-09-27 18:28:43

我正在使用 MSDN 页面中的 101 个 LINQ 示例学习 LINQ,我遇到了以下代码:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
foreach (var n in firstSmallNumbers)
{
    Console.WriteLine(n);
}

此函数的目的是"使用 TakeWhile 返回从数组开头开始的元素,直到命中小于其在数组中的位置的数字。

nindex如何确切地知道要采用哪个参数?(即n怎么知道它需要5, 4, 1, 3, 9, 8, 6, 7, 2, 0index怎么知道它会做0,1,2,3的增量......(?

lambda 参数如何在 TakeWhile 中映射

因为重载是这样定义的。来自 MSDN

public static IEnumerable<TSource> TakeWhile<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate
)

predicate参数描述如下:

一个函数,用于测试每个源元素的条件;第二个 函数的参数表示源元素的索引。

TSource参数是项,int是索引。bool是返回值。

当你写(n, index) => ...时,n采用第一个参数(TSource(,index采用第二个参数(int(。

在 lambda 表达式中,=>之前的所有内容都是方法的参数。例如,可以将 (n, index) => n >= index lambda 表达式重写为类似于以下内容的方法:

public bool CheckIfValueIsGreaterOrEqualToIndex(int value, int index)
{
    if(value >= index)
    {
         return true;
    }
    else
    {
        return false;
    }
}

因此,使用该方法,您可以为参数指定所需的任何名称(在本例中,我使用了value而不是n(。您可以在此处使用该方法代替lambda:

numbers.TakeWhile(CheckIfValueIsGreaterOrEqualToIndex);

>第一个参数n与数字上的数字相关联,第二个参数index与序列中数字的索引相关联。实际上,你给它们命名nindex并不重要,你可以命名任何名称。在任何情况下,第一个参数将与序列中的随机项相关联,第二个参数与此序列的索引相关联。

正如布拉德利在上面更正式地指出的那样,TakeWhile的定义如下:

public static IEnumerable<TSource> TakeWhile<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate
)

从上面我们可以看到,TakeWhile是在实现IEnumerable接口的类型上定义的扩展方法。现在请注意两件事,将此方法作为输入的参数及其返回类型。

它返回所提供序列中对象类型的对象序列。

它需要什么作为参数?

谓词。谓词是一种接受一些参数并返回 truefalse 的方法。谓词的参数是什么?

谓词的参数是TSource元素和intTSource元素将是序列的随机元素,int是该元素的索引。

现在这个(n, index) => n >= index是什么?

这是一个 lambda 表达式,其作用类似于谓词。

具体来说,给定名为 nindex 的变量,如果返回 true n>=index ,否则返回false. 将此表达式提供给 TakeWhile 扩展方法就像向那里传递一个Func<TSource, int, bool>谓词。所以你得到了你想要的。

最好的方法是尝试实现自己的简化TakeWhile方法:

public static List<int> MyTakeWhile(this List<int> input, Func<int, int, bool> predicate)
{
    var result = new List<int>();
    for (var i = 0; i < input.Count; i++)
    {
        if (predicate(input[i], i))
            result.Add(input[i]);
        else
            break;
    };
    return result;
}

您将在现实生活中使用yield return,并返回IEnumerable,当然,使用泛型而不是int。但想法是一样的。

如果要测试它:

var numbers = new List<int> { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var result = numbers.MyTakeWhile((n, index) => n >= index);
result.ForEach(Console.WriteLine);

它应该给出与原始TakeWhile完全相同的{5, 4}