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 返回从数组开头开始的元素,直到命中小于其在数组中的位置的数字。
n
和index
如何确切地知道要采用哪个参数?(即n
怎么知道它需要5, 4, 1, 3, 9, 8, 6, 7, 2, 0
,index
怎么知道它会做0,1,2,3的增量......(?
因为重载是这样定义的。来自 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
与序列中数字的索引相关联。实际上,你给它们命名n
和index
并不重要,你可以命名任何名称。在任何情况下,第一个参数将与序列中的随机项相关联,第二个参数与此序列的索引相关联。
正如布拉德利在上面更正式地指出的那样,TakeWhile
的定义如下:
public static IEnumerable<TSource> TakeWhile<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)
从上面我们可以看到,TakeWhile
是在实现IEnumerable
接口的类型上定义的扩展方法。现在请注意两件事,将此方法作为输入的参数及其返回类型。
它返回所提供序列中对象类型的对象序列。
它需要什么作为参数?
谓词。谓词是一种接受一些参数并返回 true
或 false
的方法。谓词的参数是什么?
谓词的参数是TSource
元素和int
。TSource
元素将是序列的随机元素,int
是该元素的索引。
现在这个(n, index) => n >= index
是什么?
这是一个 lambda 表达式,其作用类似于谓词。
具体来说,给定名为 n
和 index
的变量,如果返回 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}
。