2014-10-31 2 views
7

Я учусь LINQ с помощью 101 LINQ Samples in the MSDN page, и я наткнулся на этот код:Как сделать карту лямбда-карты в TakeWhile?

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 ...)?

+1

Я изменил ваше название. Если это не значит, что вы имели в виду, пожалуйста, измените его. – gunr2171

+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

Итак, вы говорите, что неважно, как я называю параметры? (т. е. я могу переименовать его в '(somethingElse1, somethingElse2) =>', и он все равно будет работать? –

+3

@CJ Правильно. Вы определяете анонимный метод, имена параметров зависят от вас. – BradleyDotNET

+3

@CJ Попробуйте и найдите У вас уже есть код для этого. – Servy

3

Первый параметр 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?

Это выражение лямбда, которое действует как предикат.

Specifficaly, учитывая переменные называются n и index, возвращает true если n>=index, в противном случае возвращает false. Поставляя это выражение метода TakeWhile расширения, как проходит там Func<TSource, int, bool> предикат. Итак, вы получаете то, что хотите.

+0

Не могли бы вы, пожалуйста, объяснить, где я ошибаюсь. Заранее спасибо. – Christos

+0

Не нисходящий, но он пришел к гораздо более ранней ревизии вашего ответа. Я предполагаю, что они не смотрели на эту (гораздо лучшую) версию. – BradleyDotNET

+0

@BradleyDotNET Большое спасибо за ваш комментарий. – Christos

4

В выражении лямбда все до => являются параметрами метода. В качестве примера, выражение (n, index) => n >= index лямбды может быть переписано как метод, подобный следующим:

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

Таким образом, используя этот метод, вы можете указать любое имя вы хотите параметры (в данном случае я использовал value вместо n). И вместо того, чтобы лямбда вы могли бы использовать этот метод здесь:

numbers.TakeWhile(CheckIfValueIsGreaterOrEqualToIndex); 
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.

+0

Даже если это разумный способ узнать, это не помогает научить OP, как работают лямбда-выражения. – BradleyDotNET

Смежные вопросы