Массивы (PascalABC.NET)

Материал из Информационная безопасностя
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигации Перейти к поиску

Pascal ABC.NET выбор школьника - Часть 2

Массив

Массив – хранимая нумерованная последовательность однотипных элементов с непосредственным доступом к любому элементу по его индексам, являющимся своеобразным аналогом номера.

Статические и динамические массивы

Статические массивы

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

Статические массивы – дань совместимости с более ранними версиями языка Паскаль.

Длину статического массива нельзя менять.

Динамические массивы

Динамический массив нужного размера может быть создан в том месте программы, где он впервые потребуется.

В динамических массивах индексы начинаются от нуля.

Количество элементов в динамическом массиве может меняться, но никогда не может стать отрицательным. Текущее количество элементов в массиве хранится в поле .Length.

Первый элемент массива всегда имеет индекс ноль.

Создание и инициализация массива

Статические массивы

Статический массив обычно описывается в виде

var ИмяМассива: array[m..n] of ТипЭлементов;

1 var a: array[0..12] of byte; // 13 элементов byte
2 var b, c: array[-5..8] of real;  // два массива по 14 элементов real
3 var a: array[3..6] of integer := (1, 2, 3, 4);

Динамические массивы

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

1 var a1: array of integer; // массив целых чисел
2 var p: array of real; // массив вещественных чисел
3 var q: array of boolean; // массив логических элементов

Проще всего создать динамический массив при помощи функции Arr, возвращающей такой массив. Ее аргументы – единого типа перечисленные через запятую члены будущего массива. Вместо Arr( ) удобно использовать более короткую конструкцию | |.

1 var a := Arr(1, 9, -4, 12, 40, 39, 54);
2 var d := |1, 9, -4, 12, 40, 39, 54|; // альтернативный вариант
3 var b := |3.5, 2.0, 6.417, -12.0|;
4 var c := Arr(True, 3.5 > 1.63 ** 2.95, Sin(x) > 1, False, False);

Можно совместить описание динамического массива с его созданием, для чего потребуется указать необходимую длину массива.

1 var a := new integer[10]; // массив из 10 целых элементов
2 var b := new real[7]; // массив из 7 вещественных элементов
3 var c := new boolean[4]; // массив из 4 логических элементов

Можно создать массив и обнулить его элементы следующим образом:

1 var a := |0| * 15; // создан массив из 15 нулевых элементов

В случае, когда массив был описан заранее, его длину можно установить (либо поменять) вызовом процедуры SetLength.

1 var a1: array of integer; // массив целых
2 SetLength(a1, 13); // установлена длина массива a1, равная 13

Перебор элементов в цикле

Перебор с помощью цикла с параметром

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   for var i := 0 to a.Length-1 do
4   begin
5     // a[i]
6   end;
7 end.

Перебор с помощью цикла foreach

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   foreach var x in a do
4   begin
5     // x
6   end;
7 end.

Вывод массива

Вывод массива на одной строке с помощью цикла с параметром

1 Begin
2   var a:= new integer[15];
3   for var i := 0 to a.Length-1 do
4     Write(a[i], ' ');
5 end.

Вывод массива на одной строке методом Print

Метод предполагает необязательный параметр обозначающий разделитель.

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println();
4   a.Println(', ');
5 end.

Вывод массива по одному значению в строке с помощью цикла с параметром

1 Begin
2   var a := ArrRandom(10, 10, 30);
3   for var i := 0 to a.Length-1 do
4     Writeln(a[i]);
5 end.

Вывод массива по одному значению в строке методом PrintLines

1 Begin
2   var a := ArrRandom(10, 10, 30);
3   a.PrintLines;
4 end.

Ввод элементов с клавиатуры

Ввод элементов массива с помощью цикла с параметром

1 Begin
2   var a:= new integer[15];
3   for var i := 0 to a.Length-1 do
4     Readln(a[i]);
5 end.

Ввод элементов массива с помощью функции

Единственный аргумент данной функции это количество вводимых элементов.

1 Begin
2   var a:= ReadArrInteger(15);
3 end.
4 
5 Begin
6   var a:= ReadArrReal(5);
7 end.

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

Лямбда-выражения (или просто лямбды) – термин функционального программирования. Они с успехом применяются вместо уже привычных вам процедур и функций. Собственно, они и есть процедуры или функции, только безымянные.

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

Лямбда-выражение можно записать в переменную.

Пример лямбда-выражения обозначающего подпрограмму (которая принимает целое число в качестве параметра и возвращает целое число) увеличивающую число в 2 раза.

1 var x: integer -> integer := t -> 2 * t;

Фильтрация

В программировании фильтруют обрабатываемые данные. Лишь прошедшие через фильтр данные примут участие в дальнейшей обработке.

Вы можете реализовать фильтрацию элементов массива с помощью циклов и условного оператора или с помощью функций-методов массивов.

Фильтрация с помощью цикла с параметром и условного оператора

Пример который выделяет в новый массив только положительные числа из изначального массива.

 1 Begin
 2   var a:= ArrRandom(10, -10, 10);
 3   a.Println;
 4   var b := new integer[a.Length];
 5   var index := 0;
 6   for var i := 0 to a.Length-1 do
 7   begin
 8     if (a[i] > 0) then
 9     begin
10       b[index] := a[i];
11       index += 1;
12     end;
13   end;
14   SetLength(b, index);
15   b.Println;
16 end.

Фильтрация с помощью метода Where

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var b := a.Where(x -> x > 0).ToArray;
5   b.Println;
6 end.

Фильтрация по нескольким условиям с помощью цикла с параметром и условного оператора

Пример который выделяет в новый массив только положительные делящиеся на три без остатка числа из изначального массива.

 1 Begin
 2   var a:= ArrRandom(10, -10, 10);
 3   a.Println;
 4   var b := new integer[a.Length];
 5   var index := 0;
 6   for var i := 0 to a.Length-1 do
 7   begin
 8     if (a[i] > 0) and (a[i] mod 3 = 0) then
 9     begin
10       b[index] := a[i];
11       index += 1;
12     end;
13   end;
14   SetLength(b, index);
15   b.Println;
16 end.


Фильтрация по нескольким условиям с помощью метода Where

Пример который выделяет в новый массив только положительные делящиеся на три без остатка числа из изначального массива.

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var b := a.Where(x -> (x > 0) and (x mod 3 = 0)).ToArray;
5   b.Println;
6 end.

Where с двумя параметрами: элемент + индекс

В метод Where можно передать функцию не только с одним параметром, но и с двумя. В таком случае первое значение будет самим элементом, а второе индексом массива. Например, можно вывести элементы с чётными индексами.

1 Begin
2   var a := ArrRandom(10, -20, 20);
3   a.Println;
4   a.Where((x,i) -> i mod 2 = 0).Println;
5 end.

Проекция

Проецирование сохраняет исходное количество элементов последовательности, но преобразовывает каждый элемент по некоторому правилу. Аналог – мясорубка. На входе мясо – на выходе фарш, причем именно из этого мяса. Проецирование осуществляет функция, преобразующая входные элементы по правилу, заданному лямбда-выражением.

Вы можете реализовать трансформацию всех элементов массива с помощью цикла с параметром и оператора присваивания.

Проекция с помощью цикла с параметром

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var b := new integer[a.Length];
5   for var i := 0 to a.Length-1 do
6     b[i] := a[i] * a[i];
7   b.Println;
8 end.

Проекция с помощью метода Select

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var b := a.Select(x -> x*x);
5   b.Println;
6 end.

Select с двумя параметрами: элемент + индекс

В метод Select можно передать функцию не только с одним параметром, но и с двумя. В таком случае первое значение будет самим элементом, а второе индексом массива. Например, можно увеличить элементы массива на индекс элемента.

1 Begin
2   var a := ArrRandom(10, -20, 20);
3   a.Println;
4   a.Select((x,i) -> x + i).Println;
5 end.

Сумма

Сумма циклом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var sum := 0;
5   for var i := 0 to a.Length-1 do
6     sum := sum + a[i];
7   Writeln(sum);
8 end.

Сумма методом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;  
4   Writeln(a.Sum);
5 end.

Произведение

Произведение циклом

1 Begin
2   var a:= ArrRandom(3, -10, 10);
3   a.Println;
4   var prod := 1;
5   for var i := 0 to a.Length-1 do
6     prod := prod * a[i];
7   Writeln(prod);
8 end.

Произведение методом

1 Begin
2   var a:= ArrRandom(3, -10, 10);
3   a.Println;
4   Writeln(a.Product);
5 end.

Минимум

Минимум циклом

 1 Begin
 2   var a:= ArrRandom(10, -10, 10);
 3   a.Println;
 4   var min := integer.MaxValue;
 5   for var i := 0 to a.Length-1 do
 6   begin
 7     if a[i] < min then min := a[i];
 8   end;
 9   Writeln(min);
10 end.

Минимум методом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;  
4   Writeln(a.Min);
5 end.

Максимум

Максимум циклом

 1 Begin
 2   var a:= ArrRandom(10, -10, 10);
 3   a.Println;
 4   var max := integer.MinValue;
 5   for var i := 0 to a.Length-1 do
 6   begin
 7     if a[i] > max then max := a[i];
 8   end;
 9   Writeln(max);
10 end.

Максимум методом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;  
4   Writeln(a.Max);
5 end.

Среднее

Среднее циклом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;
4   var sum := 0;
5   for var i := 0 to a.Length-1 do
6     sum := sum + a[i];
7   Writeln(sum / a.Length);
8 end.

Среднее методами

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;  
4   Writeln(a.Sum / a.Length);
5 end.

Среднее методом

1 Begin
2   var a:= ArrRandom(10, -10, 10);
3   a.Println;  
4   Writeln(a.Average);
5 end.

Заполнение массива одинаковыми значениями

Заполнение с помощью цикла с параметром

1 Begin
2   var a := new integer[10];
3   for var i := 0 to a.Length-1 do
4     a[i] := 42;
5   a.Println;
6 end.

Заполнение функцией или умножением

1 Begin
2   var a:= ArrFill(10, 42);
3   a.Println;  
4   var b := |77| * 5;
5   b.Println;
6 end.

Заполнение массива случайными значениями

Заполнение с помощью цикла с параметром

 1 Begin
 2   var a := new integer[10];
 3   for var i := 0 to a.Length - 1 do
 4     a[i] := Random(-50, 50);
 5   a.Println();
 6   
 7   var b := new real[10];
 8   for var i := 0 to b.Length - 1 do
 9     b[i] := Random(-5.0, 5.0);
10   b.Println();
11 end.

Заполнение методом

1 Begin
2   var a:= ArrRandom(10, -50, 50);
3   a.Println;  
4   var b := ArrRandomReal(10, -5, 5);
5   b.Println;
6 end.

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

n значений из индекса от 0

1 Begin
2   var a:= ArrGen(5, i -> 2 * i + 1);
3   a.Println;    
4 end.

n значений из индекса начиная с m

1 Begin
2   var a:= ArrGen(3, i -> 2 * i + 1, 10);
3   a.Println;    
4 end.

Рекуррентная последовательность с заданным первым элементом и количеством элементов

Циклом

 1 begin
 2   var a := new integer[3];
 3   var x := 105;
 4   var delta := 7;
 5   for var i := 0 to a.Length - 1 do
 6   begin
 7     a[i] := x;
 8     x += delta;
 9   end;
10   a.Println;
11 end.

Методом

1 Begin
2   var a:= ArrGen(3, 105, i -> i + 7);
3   a.Println;    
4 end.

Количество элементов, удовлетворяющих условию

Циклом

 1 begin
 2   var a := ArrRandom(10, -50, 50);
 3   a.Println;
 4   var count := 0;
 5   for var i := 0 to a.Length - 1 do
 6   begin
 7     if a[i] > 0 then count += 1;
 8   end;
 9   Writeln(count);
10 end.

Методом

1 Begin
2   var a:= ArrRandom(10, -50, 50);
3   a.Println;
4   Writeln(a.Count(x -> x > 0));
5 end.

Уникальные элементы последовательности

1 Begin
2   var a:= ArrRandom(10, 0, 10);
3   a.Println;
4   a.Distinct.Println;
5 end.

Сортировка

1 Begin
2   var a:= ArrRandom(10, 0, 10);
3   a.Println;
4   a.Sorted.Println;
5   a.SortedDescending.Println;
6 end.

Последовательность в обратном порядке

1 Begin
2   var a:= ArrRandom(10, 0, 10);
3   a.Println;
4   a.Reverse.Println;
5 end.

Срезы (выделение части массива)

a[:5] – пять первых элементов массива (индексы 0..4);

a[3:] – элементы массива, начиная с a[3] и до конца;

a[2:7] – элементы массива, начиная с a[2] и заканчивая a[6];

a[::] – весь массив (эквивалентно просто a);

a[::2] – элементы массива c индексами 0, 2, 4, … (четными);

a[1::2] – элементы массива c индексами 1, 3, 5, … (нечетными);

a[4:13:3] – элементы массива с индексами 4, 7, 10;

a[13:4:-3] – элементы массива с индексами 13, 10, 7;

a[::-1] – элементы массива в обратном порядке.

Можно указывать срезы, в которых отсчет ведется от конца массива, для чего перед значением индекса ставится знак ^. При этом a[^1] – это последний элемент массива a, a[^2] предпоследний элемент и т.д. Элемента с индексом [^0] не существует!

a[^5:] – пять последних элементов массива a;

a[^1:^6:-1] – то же, но взятые в обратном порядке;

a[:^5] – все элементы массива a, кроме пяти последних

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

Проверка с помощью цикла с параметром

1 Begin
2   var a:= ArrRandom(10, 0, 10);
3   a.Println;
4   var x := 5;
5   var exists := False;
6   for var i := 0 to a.Length-1 do
7     if a[i] = x then exists := True;
8   Writeln(exists);
9 end.

Проверка с помощью метода

1 Begin
2   var a:= ArrRandom(10, 0, 10);
3   a.Println;
4   var x := 5;  
5   Writeln(a.Contains(x));
6 end.

Проверка есть ли в последовательности элемент удовлетворяющий условию

Проверка с помощью цикла с параметром

 1 Begin
 2   var a:= ArrRandom(10, -1, 10);
 3   a.Println;
 4   var any := false;
 5   for var i := 0 to a.Length-1 do
 6   begin
 7     if a[i] < 0 then
 8       any := true;
 9   end;
10   Writeln(any);
11 end.

Проверка с помощью метода

1 Begin
2   var a:= ArrRandom(10, -1, 10);
3   a.Println;  
4   Writeln(a.Any(x -> x < 0));
5 end.

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

Проверка с помощью цикла с параметром

 1 Begin
 2   var a:= ArrRandom(10, -1, 10);
 3   a.Println;
 4   var any := true;
 5   for var i := 0 to a.Length-1 do
 6   begin
 7     if a[i] >= 0 then
 8       any := false;
 9   end;
10   Writeln(any);
11 end.

Проверка с помощью метода

1 Begin
2   var a:= ArrRandom(10, -1, 10);
3   a.Println;  
4   Writeln(a.All(x -> x >= 0));
5 end.

Поиск индексов минимального или максимального элементов

Поиск индекса минимального элемента циклом

 1 Begin
 2   var a:= ArrRandom(10, -1, 10);
 3   a.Println;  
 4   var min := integer.MaxValue;
 5   var indexMin := -1;
 6   for var i := 0 to a.Length-1 do
 7   begin
 8     if (a[i] < min) then
 9     begin
10       min := a[i];
11       indexMin := i;
12     end;
13   end;
14   Writeln(indexMin);
15 end.

Поиск индекса минимального элемента методом

1 Begin
2   var a:= ArrRandom(10, -1, 10);
3   a.Println;  
4   Writeln(a.IndexMin);
5   Writeln(a.LastIndexMin);
6 end.

Поиск индекса максимального элемента циклом

 1 Begin
 2   var a:= ArrRandom(10, -1, 10);
 3   a.Println;  
 4   var max := integer.MinValue;
 5   var indexMax := -1;
 6   for var i := 0 to a.Length-1 do
 7   begin
 8     if (a[i] > max) then
 9     begin
10       max := a[i];
11       indexMax := i;
12     end;
13   end;
14   Writeln(indexMax);
15 end.

Поиск индекса максимального элемента методом

1 Begin
2   var a:= ArrRandom(10, -1, 10);
3   a.Println;  
4   Writeln(a.IndexMax);
5   Writeln(a.LastIndexMax);
6 end.

Пересечение (общие элементы) двух массивов

1 Begin
2   var a := ArrRandom(10, -10, 10);
3   var b := ArrRandom(10, -10, 10);
4   a.Println;
5   b.Println;
6   a.Intersect(b).Println();
7 end.

Объединение (все уникальные элементы) двух массивов

1 Begin
2   var a := ArrRandom(10, -10, 10);
3   var b := ArrRandom(10, -10, 10);
4   a.Println;
5   b.Println;
6   a.Union(b).Println();
7 end.

Разность двух массивов (элементы первого массива, которых нет во втором)

1 Begin
2   var a := ArrRandom(10, -10, 10);
3   var b := ArrRandom(10, -10, 10);
4   a.Println;
5   b.Println;
6   a.Except(b).Println();
7 end.

Объединение методов

Большинство методов для обработки последовательностей возвращает последовательность в виде результата. К ней в свою очередь можно применить те же методы, что позволяет применять несколько методов в одном вызове. Если строка вызовов становится длинной её разбивают выделяя каждый новый метод на новую строку, которая начинается с точки. Все строки, кроме первой, пишутся с отступом, чтобы показать принадлежность к одной строке кода.

Сумма положительных элементов

Например сначала можно отобрать из массива только положительные элементы, затем найти их сумму и третьим методом вывести её на экран.

1 Begin
2   var a := ArrRandom(10, -20, 20);
3   a.Println;
4   a.Where(x -> x > 0).Sum.Println;
5 end.

Квадраты элементов, которые больше 5

1 Begin
2   var a := ArrRandom(10, -20, 20);
3   a.Println;
4   a.Where(x -> x > 5)
5     .Select(x -> x * x)
6     .Println;
7 end.

Сумма индексов чётных чисел

Например, мы можем преобразовать список чисел в список пар (кортежей) чисел и их индексов (.Select((x,i) -> (x,i))). Затем пары чисел можно обрабатывать как одну переменную пары. Эта пара является кортежем. Вы можете упаковать до 7 переменных. Доступ к элементам кортежа происходит через свойства Item1, Item2 и так далее. Или вы можете распаковать кортеж в переменные с помощью слэша \ (например, \(x,i)). Тогда первая переменная будет записана в переменную x, а вторая в переменную i.

1 Begin
2   var a := ArrRandom(10, -20, 20);
3   a.Println;
4   a.Select((x,i) -> (x,i))
5     .Where(pair -> pair.Item1 mod 2 = 0)
6     .Select(\(x,i) -> i)
7     .Sum.Println;
8 end.