Операции Take, TakeWhile, Skip и SkipWhile

84

Операции разбиения (partitioning) позволяют вернуть выходную последовательность, которая является подмножеством входной последовательности.

Take

Операция Take возвращает указанное количество элементов из входной последовательности, начиная с ее начала. Операция Take имеет один прототип, описанный ниже:


public static IEnumerable<T> Take<T>( 
    this IEnumerable<T> source, 
    int count);

Этот прототип указывает, что Take принимает входную последовательность и целое число count, задающее количество элементов, которые нужно вернуть, и возвращает объект, который при перечислении выдает первые count элементов из входной последовательности.

Если значение count больше количества элементов во входной последовательности, тогда каждый элемент из нее попадает в выходную последовательность.

Ниже показан пример использования операции Take:

string[] cars = { "Nissan", "Aston Martin", "Chevrolet", "Alfa Romeo", "Chrysler", "Dodge", "BMW",
        "Ferrari", "Audi", "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

IEnumerable<string> auto = cars.Take(5);

foreach (string str in auto)
        Console.WriteLine(str);

Этот код вернет первые пять элементов из массива cars. Полученный результат выглядит следующим образом:

Использование LINQ-операции Take

TakeWhile

Операция TakeWhile возвращает элементы из входной последовательности, пока истинно некоторое условие, начиная с начала последовательности. Остальные входные элементы пропускаются.

Операция Take While имеет два прототипа, описанные ниже:

Первый прототип TakeWhile
public static IEnumerable<T> TakeWhile<T>( 
       this IEnumerable<T> source,
       Func<T, bool> predicate);

Эта операция TakeWhile принимает входную последовательность и делегат метода-предиката, а возвращает объект, перечисление по которому выдает элементы до тех пор, пока метод-предикат не вернет false. Метод-предикат принимает элементы по одному из входной последовательности и возвращает признак того, должен элемент включаться в выходную последовательность или нет. Если да, обработка входных элементов продолжается. Как только метод-предикат вернет false, никакие последующие входные элементы не обрабатываются.

Второй прототип TakeWhile
public static IEnumerable<T> TakeWhile<T> ( 
       this IEnumerable<T> source, 
       Func<T, int, bool> predicate);

Этот прототип подобен первому, за исключением того, что метод-предикат получает вдобавок индекс элемента из входной последовательности, начинающийся с нуля.

Ниже приведен пример вызова первого прототипа:

string[] cars = { "Nissan", "Chevrolet", "Alfa Romeo", "Chrysler", "Dodge", "BMW", "Aston Martin",
                            "Ferrari", "Audi", "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

IEnumerable<string> auto = cars.TakeWhile(s => s.Length < 12);

foreach (string str in auto)
        Console.WriteLine(str);

В приведенном коде входные элементы извлекаются до тех пор, пока их длина не превышает 11 символов. Ниже показан результат:

Использование первого прототипа TakeWhile

Элемент, который заставил операцию TakeWhile прекратить обработку входной последовательности — Aston Martin. Рассмотрим пример второго прототипа операции TakeWhile:

IEnumerable<string> auto = cars.TakeWhile((s, i) => s.Length < 12 && i < 5);

foreach (string str in auto)
        Console.WriteLine(str);

Код в этом примере прекращает выполнение, когда входной элемент превысит 11 символов в длину или когда будет достигнут шестой элемент — в зависимости от того, что произойдет раньше. Вот результат:

Использование второго прототипа TakeWhile

В этом случае обработка остановилась по достижении шестого элемента.

Skip

Операция Skip пропускает указанное количество элементов из входной последовательности, начиная с ее начала, и выводит остальные.

Операция Skip имеет один прототип, описанный ниже:

public static IEnumerable<T> Skip<T>( 
          this IEnumerable<T> source, int count);

Операция Skip получает входную последовательность и целое число count, задающее количество входных элементов, которое должно быть пропущено, и возвращает объект, который при перечислении пропускает первые count элементов и выводит все последующие элементы.

Ниже приведен пример вызова операции Skip:

string[] cars = { "Nissan", "Chevrolet", "Alfa Romeo", "Chrysler", "Dodge", "BMW", "Aston Martin",
                            "Ferrari", "Audi", "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

IEnumerable<string> auto = cars.Skip(5);

foreach (string str in auto)
        Console.WriteLine(str);

В данном примере пропускаются первые 5 элементов. Обратите внимание, что в следующем выводе действительно пропущены первые пять элементов входной последовательности:

Вызов LINQ-операции Skip

SkipWhile

Операция SkipWhile обрабатывает входную последовательность, пропуская элементы до тех пор, пока условие истинно, а затем выводит остальные в выходную последовательность. У операции SkipWhile есть два прототипа, описанные ниже:

public static IEnumerable<T> SkipWhile<T>( 
      this IEnumerable<T> source, 
      Func<T, bool> predicate);

Операция SkipWhile принимает входную последовательность и делегат метода-предиката, а возвращает объект, который при перечислении пропускает элементы до тех пор, пока метод-предикат возвращает true. Как только метод-предикат вернет false, операция SkipWhile начинает вывод всех прочих элементов. Метод-предикат принимает элементы входной последовательности по одному и возвращает признак того, должен ли элемент быть пропущен из входной последовательности.

Второй прототип SkipWhile
public static IEnumerable<T> SkipWhile<T>( 
     this IEnumerable<T> source, 
     Func<T, int, bool> predicate);

Этот прототип подобен первому во всем, за исключением дополнительного параметра — индекса элемента из входной последовательности, начинающегося с нуля.

Ниже приведен пример вызова первого прототипа операции SkipWhile:

string[] cars = { "Alfa Romeo", "Aston Martin", "Audi", "Nissan", "Chevrolet",  "Chrysler", "Dodge", "BMW", 
                            "Ferrari",  "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

IEnumerable<string> auto = cars.SkipWhile(s => s.StartsWith("A"));

foreach (string str in auto)
        Console.WriteLine(str);

В этом примере метод SkipWhile должен пропускать элементы до тех пор, пока они начинаются с буквы "А". Все остальные элементы выдаются в выходную последовательность. Результат предыдущего запроса выглядит так:

Использование первого прототипа SkipWhile

Теперь рассмотрим пример использования второго прототипа SkipWhile:

string[] cars = { "Alfa Romeo", "Aston Martin", "Audi", "Nissan", "Chevrolet",  "Chrysler", "Dodge", "BMW", 
                            "Ferrari",  "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};

IEnumerable<string> auto = cars.SkipWhile((s, i) => s.StartsWith("A") && i < 10);

foreach (string str in auto)
        Console.WriteLine(str);

В данном примере входные элементы пропускаются до тех пор, пока они начинаются с буквы "А" или пока не будет достигнут десятый элемент. Остальные элементы выдаются в выходную последовательность.

Пропуск элементов был прекращен, как только встретился элемент Nissan, поскольку он начинается с N, хотя его индексом является 3.

Пройди тесты
Лучший чат для C# программистов