lambda参数如何在TakeWhile中映射?

时间:2014-10-31 20:02:03

标签: c# linq lambda

我正在使用101 LINQ Samples in the MSDN page学习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, 0将如何知道index如何知道它将增加0,1,2,3 ...)?

4 个答案:

答案 0 :(得分:9)

因为过载是这样定义的。来自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)。

答案 1 :(得分:4)

在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);

答案 2 :(得分:3)

第一个参数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表达式,其作用类似于谓词。

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

答案 3 :(得分:2)

最好的方法是尝试实现自己的简化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);

它应该提供{5, 4},它与原始TakeWhile完全相同。