Занятие 6. Pascal abc.net: Lambda выражения и последовательности

Рассматривается работа с лямбда-выражениями в abc.net

Лямбда-выражения

Генерация последовательностей и массивов при помощи лямбда-выражений

Для генерации последовательностей при помощи лямбда-выражений используются следующие функции:

  • SeqGen(count: integer; f: integer -> T): sequence of T;
  • begin
    var sq:=SeqGen(5,x->x+1);
    sq.println; // 1 2 3 4 5
    end.
  • SeqGen(count: integer; first: T; next: T -> T): sequence of T;
  • begin
    var sq:=SeqGen(5, 4, x->x+1);
    sq.println; // 4 5 6 7 8
    end.
  • SeqGen(count: integer; first,second: T; next: (T,T) -> T): sequence of T;
  • begin
    var sq:=SeqGen(5, 1,3, (x,y)->x+y);
    sq.println; // 1 3 4 7 11
    end.
  • SeqWhile(first: T; next: T -> T; pred: T -> boolean): sequence of T;
  • Добавляется логическое условие:

    begin
    var sq:=seqWhile(2,x->x*2,x->x<=1024);
    sq.println; // 2 4 8 16 32 64 128 256 512 1024
    end.
  • SeqWhile(first,second: T; next: (T,T) -> T; pred: T -> boolean): sequence of T;
  • SeqGen(count: integer; f: integer -> T): sequence of T;
  • То же для массивов с заменой Seq на Arr – возвращают array of T

Генерация бесконечных последовательностей

  • Cycle()
  • Повторение блока последовательности

    Seq(1,2,10,5).Cycle().Take(15).Println; // 1 2 10 5 1 2 10 5 1 2 10 5 1 2 10

    Take используется для ограничения

  • Repeat
  • Бесконечная последовательность из числа

    var q:=55.Repeat.Take(10).Println; // 55 55 55 55 55 55 55 55 55 55
  • Step
  • Генерация бесконечной последовательности с шагом

    var q:=5.Step(2).Take(10).Println; // 5 7 9 11 13 15 17 19 21 23
  • Iterate
  • Генерация бесконечной последовательности при помощи лямбда-функции

    var q:=10.Iterate(x->x-2).Take(10).Println; // 10 8 6 4 2 0 -2 -4 -6 -8

Фильтрация последовательностей

  • Where(T -> boolean)
  • var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Where(x->x mod 2=0); // 2 4 6 8 10
  • Where((T, integer) -> boolean)
  • begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Where((x,i)->i mod 2=0); // 1 3 5 7 9
    s1.Println;
    end.

    Здесь x — это элемент, а i — индекс элемента. Т.о. отбираются элементы с четными индексами

Отрезание кусков последовательностей:

  • Take(count)
  • begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Take(2); // 1 2
    s1.Println;
    end.
  • TakeLast(count)
  • Skip(count)
  • begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Skip(2); // 3 4 5 6 7 8 9 10
    s1.Println;
    end.
    begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Skip(3)+s.Take(3); // 4 5 6 7 8 9 10 1 2 3
    s1.Println;
    end.
  • SkipLast(count)
  • TakeWhile(T -> boolean)
  • TakeWhile((T, integer) -> boolean)
  • SkipWhile(T -> boolean)
  • SkipWhile((T, integer) -> boolean)
  • Slice(from,step[,count]: integer): sequence of T;
  • Distinct
  • Выбор только неповторяющихся элементов

    var a:=Seq(1,3,1,4,1,5);
    a.Distinct.Print; // 1 3 4 5
  • Reverse
  • Реверсирует последовательность

    var a:=Seq(1,3,1,4,1,5);
    a.Reverse.Print; // 5 1 4 1 3 1

Проекция последовательностей

При использовании проекции преобразуется каждый элемент последовательности (в отличие от where)

  • Select(T -> TRes)
  • begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Select(x->x*x); // 1 4 9 16 25 36 49 64 81 100
    s1.Println;
    end.

    Комбинация проекции и фильтрации:

    begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Where(x -> x mod 2 = 0).Select(x->x*x); // 4 16 36 64 100
    s1.Println;
    end.
  • Select((T, integer) -> TRes)
  • Выборка не только по элементу, но и по его индексу
    Пример печати квадратов элементов с их индексами (в виде кортежей):

    begin
    var s:=seqGen(10,x->x+1); // 1 2 3 4 5 6 7 8 9 10
    var s1:=s.Select((x,i)->(i+1,x*x)); 
    s1.Println;//(1,1) (2,4) (3,9) (4,16) (5,25) (6,36) (7,49) (8,64) (9,81) (10,100)
    end.
  • SelectMany(T -> sequence of TRes)
  • SelectMany((T, integer) -> sequence of TRes)

Сортировка или упорядочивание последовательностей

  • Sorted
  • SortedDescending
  • OrderBy(T -> TKey)
  • var s:=Seq(('Ivanov',20,1),('Petrov',19,2),('Popov',21,1));
    s.OrderBy(x->x[0]).Println; // (Ivanov,20,1) (Petrov,19,2) (Popov,21,1)
    s.OrderBy(x->x[1]).Println; // (Petrov,19,2) (Ivanov,20,1) (Popov,21,1)
  • OrderByDescending(T -> TKey)
  • Пример: Данная функция может быть использована, например, для поиска k максимумов в массиве:

    begin
    var a:=Arr(1,3,5,2,7,9,0);
    var k:=3;
    a.OrderByDescending(x->x).Distinct.Take(k).Print; // 9 7 5
    end.
  • ThenBy(T -> TKey)
  • ThenByDescending(T -> TKey)

Вычисление скаляра

  • Count([T -> boolean]): integer
  • var a:=Arr(1,2,3,4,5);
    var b:=a.Count(x->x mod 2 <>0); // 3 нечетных элемента

    В примере Count — это фильтр (как Where), который считает кол-во нечетных элементов.

  • Average: double
  • Average(T -> числовой_тип): double
  • Sum: числовой_тип
  • Sum(T -> числовой_тип): числовой_тип
  • Average и Sum — это не фильтр, а проекция (как Select)

    Пример вывода среднего возраста студентов:

    var students:=Seq(('Ivanov',20,1),('Petrov',19,2),('Popov',21,1));
    var i:=students.Average(x->x[1]); // 20
  • Max: T
  • Пример:Дан массив a: 1,3,5,2,7,9,0. Необходимо найти три первых максимума. Максимумы не должны быть равны друг другу:

    begin
    var a:=Arr(1,3,5,2,7,9,0);
    var max:=a.Max;
    var max1:=a.Where(x->x<max).Max;
    var max2:=a.Where(x->x<max1).Max;
    print(max,max1,max2); // 9 7 5 
    end.
  • Max(T -> TRes): TRes
  • Min: T
  • Min(T -> TRes): TRes
  • Пример вывода минимального показателя рейтинга студентов:

    var students:=Seq(('Ivanov',20,40),('Petrov',19,25),('Popov',21,35));
    var i:=students.Min(x->x[2]); // 25
  • MinBy(selector: T -> TKey): T
  • Это модификация обычной функции Min. Выводит всю запись:

    var students:=Seq(('Ivanov',20,40),('Petrov',19,25),('Popov',21,35));
    var i:=students.MinBy(x->x[2]); // (Petrov,19,25)
  • MaxBy(selector: T -> TKey): T
  • Aggregate((T, T) -> T): T
  • Aggregate функция-накопитель. Как сумматор, произведение элементов, конкатенация строк.

    Замена стандартного алгоритма нахождения суммы элементов последовательности:
    Обычно сумма находится:

    var q:=Seq(3,9,7,2);
    var s:=0;
    foreach var x in q do
      s+=x;
    print(s); //21

    Теперь используем функцию:

    var q:=Seq(3,9,7,2);
    print(q.Aggregate(0,(s,x) -> s+x)); // 21

    Пример: выполнить произведение элементов последовательности:

    var q:=Seq(3,9,7,2);
    print(q.Aggregate(1,(p,x) -> p*x)); // 378

    Пример: выполнить конкатенацию элементов последовательности:

    var q:=Seq('a','b','c');
    print(q.Aggregate('',(s,x) -> s+x)); // abc
  • Aggregate(TRes seed, (TRes, T) -> TRes): TRes
  • JoinIntoString([delim: string]): string;

Эти методы еще называются методами свертки последовательностей в скаляр (fold).
Пример свертки в строку:

var a:=Arr(1,3,5); // массив
var s:=a.JoinIntoString.Println; // 1 3 5 - строка

Вычисление логического значения

  • All(T -> boolean)
  • Пример: Доказать, что в последовательности все числа нечетные:

    begin
    var sq:=Seq(1,3,5,2,7,9,0);
    print(sq.All(x->x mod 2 <>0)); // False  
    end.
  • Any(T -> boolean)
  • Пример: Есть ли в последовательности числа большие 7:

    begin
    var sq:=Seq(1,3,5,2,7,9,0);
    print(sq.Any(x->x > 7)); // True   
    end.
  • Contains(x: T) // можно x in s
  • SequenceEqual(second: sequence of T)
  • Пример: Доказать, что в последовательности все числа различны:

    begin
    var sq:=Seq(1,3,5,2,7,9,0);
    print(sq.SequenceEqual(sq.Distinct)); // True 
    end.

    В примере сравнивается исходная последовательность с то же последовательностью, только без повторений.

Сцепление и операции над множествами

  • Concat(second: sequence of T) // можно s1 + s2 или a1 + a2
  • begin
    var a:=Seq(1,2,3,4);
    var b:=Seq(3,4,5);
    var sq:=a.Concat(b).Println; // 1 2 3 4 3 4 5
    end.
  • Union(second: sequence of T)
  • begin
    var a:=Seq(1,2,3,4);
    var b:=Seq(3,4,5);
    var sq:=a.Union(b).Println; // 1 2 3 4 5
    end.
  • Intersect(second: sequence of T)
  • begin
    var a:=Seq(1,2,3,4);
    var b:=Seq(3,4,5);
    var sq:=a.Intersect(b).Println; // 3 4
    end.
  • Except(second: sequence of T)
  • begin
    var a:=Seq(1,2,3,4);
    var b:=Seq(3,4,5);
    var sq:=a.Except(b).Println; // 1 2
    end.

Объединение, разделение

  • Zip(second: sequence of T, (T,T)->T1): sequence of T1
  • Пример: сложение элементов двух последовательностей:

    var a:=Seq(3,9,7,13,2,4,2);
    var b:=Seq(2,4,7,1,5,4);
    var sq:=a.Zip(b,(xa,xb)->(xa+xb)).Println; // 5 13 14 14 7 8

    Пример: В массиве элементов 3 9 7 1 2 4 вывести количество элементов, меньших своего левого соседа. Выполнить при помощи последовательности

    Проблема: В последовательностях нет индексов элементов, и в каждый момент времени доступен только 1 элемент, т.о. не возможно сравнение предыдущего элемента со следующим.
    Выполнение:

    begin
    var a:=Seq(3,9,7,13,2,4);
    var b:=a.Skip(1); // [9,7,13,2,4]
    // Теперь можно сравнить две последовательности
    var sq:=a.Zip(b,(xa,xb)->(xa,xb)).Println; // (3,9) (9,7) (7,13) (13,2) (2,4)
    println(sq.Count(x->x[0]>x[1])); // 2
    // ИЛИ вывод этих элементов
    sq.Where(x->x[0]>x[1]).Select(x->x[1]).Println;
    end.
  • Cartesian(second: sequence of T1): sequence of (T,T1);
  • Декартово произведение массивов в одном массиве.

    begin
    var x1:=Arr('Ivanov','Petrov','Sidorov');
    var x2:=Arr('Pizza','hamburger','sweets');
    x1.Cartesian(x2).Println;
    { (Ivanov,Pizza) (Ivanov,hamburger) (Ivanov,sweets) (Petrov,Pizza) 
    (Petrov,hamburger) (Petrov,sweets) (Sidorov,Pizza) (Sidorov,hamburger) (Sidorov,sweets)} 
    end.
  • ZipTuple(second: sequence of T1): sequence of (T,T1);
  • Кортежное объединение последовательностей.

    begin
    var a:=Seq(1,3,5,2,8);
    var b:=Seq(9,7,2,3,8,4);
    a.ZipTuple(b).Println; // (1,9) (3,7) (5,2) (2,3) (8,8)
    end.
  • sequence of (T,T1).UnZipTuple: (sequence of T,sequence of T1);
  • SplitAt(ind: integer): (sequence of T,sequence of T);
  • Partition(cond: T->boolean): (sequence of T,sequence of T);
  • Деление последовательности по условию.

    begin
    var a:=Range(-5,5).Println; // -5 -4 -3 -2 -1 0 1 2 3 4 5
    (var q1,var q2):= a.Partition(x->x>=0); 
    Println (q1,q2) // [0,1,2,3,4,5] [-5,-4,-3,-2,-1]
    end.

    Здесь используется кортежное присваивание.

  • Interleave(second: sequence of T): sequence of T;
  • Numerate([from: integer]): sequence of (integer,T);
  • Нумерация некоторой последовательности:

    begin
    var a:=Seq(11,12,1,3,7);
    a.Numerate.Println // (1,11) (2,12) (3,1) (4,3) (5,7)
    end.
  • Tabulate(F: T->T1): sequence of (T,T1);
  • Pairwise: sequence of (T,T);

Преобразование в контейнер

  • ToArray: array of T;
  • ToHashSet: HashSet;
  • ToSortedSet: SortedSet;

Поэлементные операции

  • First([T -> boolean])
  • Взять 1-й элемент:

    var a:=Arr(1,3,5);
    print(a.First); // 1
  • Last([T -> boolean])
  • Single([T -> boolean])
  • ElementAt(integer index)
  • Взять k-й элемент:

    var a:=Arr(1,3,5);
    print(a.ElementAt(2)); // 5

Действия над элементами

  • ForEach(action: T -> ())
  • Решение задач

    Генерация последовательностей

    Задание 1: Используя lambda-выражения, создайте последовательность из N четных чисел, начиная с 10 (SeqGen)


    Задание 2: Создайте последовательность 1 3 9 27 81 243 729 2187 6561 19683


    Задание 3: Создайте последовательность из 15 чисел 2 1 0.5 0.25 0.125 0.0625 0.03125 0.015625 … (указав первый элемент и функцию получения следующего)


    Задание 4: Создайте последовательность 2017 2012 2007 2002 1997 1992 1987 1982 1977 1972


    Пример: Создайте последовательность из N чисел Фибоначчи

    Выполнение:

    var n:=readInteger;
    var sq3:=SeqGen(n,1,1,(x,y)->x+y);
    sq3.println();

    Задание 5: Создайте последовательность из N чисел, заданных итерационным процессом: а1=5, акк-1/2-1, к=2,3,…


    Пример: Создайте последовательность из N чисел, заданных итерационным процессом: а1=2, ак=(ак-1+1)*ак-1, к=2,3,…

    Выполнение:

    var sq5:=SeqGen(n,2,x->(x+1)*x);
    sq5.println();

    Задание 6: Создайте последовательность из N чисел, заданных итерационным процессом: а1=1, а2=2, акк-1+2ак-2, к=3,…


    Задание 7: Создайте последовательность из N чисел, заданных итерационным процессом: а1=1, а2=2, ак=(ак-1к-2)/2, к=3,…


    Задание 8: Придумайте свою последовательность

    Пример: Из последовательностей, созданных в пунктах 2.1-2.9, выбрать те элементы (если это возможно), которые:
    а) четные; б) кратные 5; в) отрицательные; д) нечетные

    Выполнение:

    writeln('Четные ');
      var s1:=sq.Where(x->x mod 2 =0).Println;
      s1:=sq2.Where(x->x mod 2 =0).Println;
      s1:=sq3.Where(x->x mod 2 =0).Println;
      s1:=sq5.Where(x->x mod 2 =0).Println;
      s1:=sq6.Where(x->x mod 2 =0).Println;
     
      writeln('Кратные 5 ');
      var s2:=sq2.Where(x->x mod 5 =0).Println;
      s2:=sq3.Where(x->x mod 5 =0).Println;
      s2:=sq5.Where(x->x mod 5 =0).Println;
      s2:=sq6.Where(x->x mod 5 =0).Println;
     
      writeln('Отрицательные ');
      s2:=sq2.Where(x-> x < 0 ).Println;
      s2:=sq3.Where(x->x < 0).Println;
      s2:=sq5.Where(x->x < 0).Println;
      s2:=sq6.Where(x->x < 0).Println;
     
      writeln('Нечетные ');
      s1:=sq.Where(x->x mod 2 <>0).Println;
      s1:=sq2.Where(x->x mod 2 <>0).Println;
      s1:=sq3.Where(x->x mod 2 <>0).Println;
      s1:=sq5.Where(x->x mod 2 <>0).Println;
      s1:=sq6.Where(x->x mod 2 <>0).Println;

    Пример: Создайте последовательность из нечетных чисел, начиная с 1, и которые не превышают 100000 (SeqWhile). Выберите элементы, кратные 3 и оставьте из них 10 чисел

    Выполнение:

    seqWhile(1,x->x + 2,x->x<=10000).Where(x->x mod 3=0).take(100).Println;

    Задание 9: Найдите сумму первых чисел Фибоначчи, которые однозначные или двухзначные


    Пример: Найдите среднее арифметическое чисел Фибоначчи, которые четные и трехзначные

    Выполнение:

    println(seqWhile(1,1,(x,y)->x+y,x->x div 1000=0).where (x-> (x>100)and(x<=999)and (x mod 2 =0)).average) ;

    Задание 10: Найдите количество чисел Фибоначчи, которые лежат в диапазоне от 100 до 5000


    Пример: Найдите максимальное среди четных и минимальное среди нечетных чисел введенной последовательности целых чисел

    Выполнение:

    var sq11:=Arr(1,2,3,4,5,6,7,-10,-12);
      println(sq11.Where(x->x mod 2=0).max);
    println(sq11.Where(x->x mod 2<>0).min);

    Пример: Выдайте 20 элементов последовательности , каждый элемент которой является квадратом нечетных чисел

    Выполнение:

    var sq12:=SeqGen(125,1,1,(x,y)->x+y).Where (x-> x mod 2<>0).Select(x->x*x).Take(20);
    {?? var sq12:=SeqGen(125,1,1,(x,y)->x+y).Where (x-> sqrt(x) mod 2<>0).Take(20);}
    println(sq12);

    Запросы в последовательностях

    Пример: Дана целочисленная последовательность. Найти сумму всех отрицательных элементов с порядковыми элементами от а1 до а2 включительно (1 <= a1 < a2).

    Выполнение:

    begin
    var a:=seqRandomInteger(10,-10,10);
    var a1:=readInteger;
    var a2:=readInteger;
    assert(a1<a2);
    assert(a1>=1);
    var b1:=a.Skip(a1).take(a2-a1+1).where(x->x<0).Sum;
    println('результат: ',b1);
    end.

    Задание 11: Дана целочисленная последовательность. Найти максимальный элемент среди трехзначных, расположенных на позициях, начиная с k-ой.


    Задание 12: Дана последовательность Фибоначчи. Найти сумму квадратов элементов последовательности, пропустив первые 10


    Задание 13: Дана последовательность чисел. Найти минимальный элемент среди удвоенных модулей элементов


    Пример: Дана целочисленная последовательность. Найти последовательность из единичных разрядов каждого элемента последовательности. Затем получить сумму этой последовательности без учета повторяющихся элементов

    Выполнение:

    begin
    var g: sequence of integer;
    g:=Seq(23,39,77,62);
    println(g.select(x->x mod 10).Sum);
    end.

    Задание 14: Дана целочисленная последовательность. Получить последовательность, в которой элемент является квадратным корнем соответствующего элемента исходной последовательности


    Задание 15: Создать 3 бесконечные последовательности: первую — из цифр 5, вторую — из чисел 2, 5, 8, 11, …; третью — как повторения чисел 1, 2, 10, 5 (Seq(1,2,10,5).Cycle()). Вывести по 100 элементов каждой


    Пример: Найдите объединение 25 чисел первой последовательности из предыдущего задания и 40 элементов третьей последовательности того же задания; пересечение 30 элементов второй последовательности и 20 элементов третьей. Выведите получившиеся последовательности без повторений

    Выполнение:

    ...
     r1.Take(25).Union(r4.Take(40)).distinct.Println;
     r2.Take(30).Intersect(r4.Take(20)).distinct.Println;
    ...

    Пример: Даны 2 целочисленные последовательности. Найти минимальный элемент разности первой со второй

    1 Вариант: разность элементов последовательностей и поиск минимума
    Выполнение:

    begin
    var a:=Seq(3,9,7,13,2,4,2);
    var b:=Seq(2,4,7,1,5,4);
    var sq:=a.Zip(b,(xa,xb)->(xa-xb)).Println; // 1 5 0 12 -3 0
    PrintLn(sq.Min) // -3
    end.

    2 Вариант: разность последовательностей и поиск минимума
    Выполнение:

    begin
    var a:=Seq(3,9,7,13,2,4,2);
    var b:=Seq(2,4,7,1,5,4);
    var sq:=a.Except(b).Println; // 3 9 13
    PrintLn(sq.Min) // 3
    end.

    Задание 16: Даны 2 целочисленные последовательности. Найти последовательность, в которой сначала располагаются элементы первой, не встречающиеся во второй, а затем элементы второй, не встречающиеся в первой последовательности


    Пример: Дана целочисленная последовательность. Найти 2 последовательности: в первой все четные числа, во второй — остальные

    Выполнение:

    begin
    var a:=Seq(1,2,3,4,5,6);
    (var q1,var q2):=a.Partition(x->x mod 2 = 0);
    println(q1,q2) // [2,4,6] [1,3,5] 
    end.

    Задание 17: Дана целочисленная последовательность. Разбить на 2 последовательности: в первую поместить первые k чисел, остальные — во вторую


    Пример 13: Дана целочисленная последовательность. Получить последовательность из двузначных чисел, записанных наоборот (число 39 исходной последовательности преобразуется в 93). Найти средне арифметическое нечетных чисел без учета первых 10 элементов

    Выполнение:

    // ??? неверное решение
    begin
    var r: sequence of integer;
    var t1,t2,t3: sequence of integer;
    r:=range(85,95); // 85,86,87,88,89,90,91,92,93,94,95] 
    println(r);
    t1:=r.Select(x-> x mod 10).Println;//5 6 7 8 9 0 1 2 3 4 5
    t2:=r.Select(x-> x div 10).Println; //8 8 8 8 8 9 9 9 9 9 9
    var sq:=t1.Zip(t2,(xa,xb)->(xa,xb)).Println; //(5,8) (6,8) (7,8) (8,8) (9,8) (0,9) (1,9) (2,9) (3,9) (4,9) (5,9)
    t1.ZipTuple(t2).Println;//(5,8) (6,8) (7,8) (8,8) (9,8) (0,9) (1,9) (2,9) (3,9) (4,9) (5,9)
    end.
    Поделитесь уроком с коллегами и друзьями:
    2 комментария

      Ирина

      У вас ошибка в примере программы после задания 13. Там при каждом обращении к случайной последовательности она генерируется снова.
      begin
      var g,j: sequence of integer;
      g:=seqRandomInteger(10,10,1000);
      j:=g.Select(x->x mod 10);
      writeln(j.sum);
      end.
      {929 857 829 22 367 342 864 603 309 464
      8 1 6 0 8 9 9 5 5 3
      44
      }

        admin

        Спасибо! Исправлено

    Добавить комментарий

    Ваш e-mail не будет опубликован. Обязательные поля помечены *

    *
    *

    Вставить формулу как
    Блок
    Строка
    Дополнительные настройки
    Цвет формулы
    Цвет текста
    #333333
    Используйте LaTeX для набора формулы
    Предпросмотр
    \({}\)
    Формула не набрана
    Вставить