May 11

Задачи на массивы - прагматичный подход

Данный текст опубликован в рамках подготовки к экзамену учеников Компьютерной школы мехмата ЮФУ (sunschool.mmcs.sfedu.ru) по курсу "Программирование 2 ступень".

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

Описание массива и выделение памяти

var a: array of integer := new integer[10];

Можно без указания типа:

var a := new integer[10];

Если в задаче требуется создать массив из N элементов, то N надо предварительно ввести:

var N := ReadInteger; var a := new integer[N];

Цикл по массиву

for var i:=1 to a.Length-1 do Print(a[i])

или

foreach var x in a do Print(x)

В случае foreach невозможно изменение элементов.

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

Массив можно ввести циклом

var N := ReadInteger; var a := new integer[N]; for var i:=1 to a.Length-1 do a[i] := ReadInteger;

или методом

var N := ReadInteger; var a := ReadArrInteger(N);

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

a.Println;

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

Для проверки, есть ли элемент в массиве, используется операция in:

3 in a (3 in a) or (4 in a)

Найти индекс первого элемента, равного чему то:

var ind := a.IndexOf(3); // индекс первой 3 или -1 если не найдено

Найти индекс первого элемента, удовлетворяющего условию:

var ind := a.FindIndex(x -> x mod 2 = 0); // индекс первого четного или -1 если не найдено

FindIndex можно также использовать для проверки, есть ли элементы, удовлетворяющие условию:

var Has := a.FindIndex(x -> x in 3..5) <> -1; // есть ли элементы от 3 до 5

Генерация массива по заданному правилу

var a := ArrFill(N,1); // заполнить N элементов значением 1

Для заполнения каждого элемента по правилу a[i] := i + 1 пользуемся функцией ArrGen:

var a := ArrGen(N, i -> i+1);

Но можно и циклом:

var a := new integer[N]; for var i:=1 to a.Length-1 do a[i] := i + 1;

Для заполнения массива, в котором задан первый элемент, а каждый следующий определяется по предыдущему, пользуемся

var a := ArrGen(N, 1, x -> следующий);

Здесь N - количество элементов, 1 – первый элемент.

Например, если каждый следующий больше предыдущего на 2:

var a := ArrGen(N, 1, x -> x + 2);

Если же каждый следующий больше предыдущего в 2 раза:

var a := ArrGen(N, 1, x -> x * 2);

Преобразование элементов по заданному правилу

Будем считать массив a заданным (например, введенным с клавиатуры).

Чтобы увеличить все элементы массива на 1, пользуемся методом-процедурой Transform:

a.Transform(x -> x + 1)

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

a := a.Select(x -> x + 1).ToArray;

Если некоторые элементы надо преобразовать по одному правилу, а остальные – по другому или не преобразовывать вовсе, то лучше воспользоваться циклом. Например, для обнуления нечетных:

for var i:=1 to a.Length-1 do if a[i] mod 2 <> 0 then a[i] := 0;

Если нечетные надо уменьшить на 1, а четные увеличить на 1:

for var i:=1 to a.Length-1 do if a[i] mod 2 <> 0 then a[i] -= 1 else a[i] += 1;

Немного менее понятным будет код с Transform и использованием условной операции:

a.Transform(x -> x mod 2 = 0 ? x - 1 : x + 1);

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

Если в массиве надо отобрать элементы, удовлетворяющие определенному условию, это называется фильтрацией. Фильтрацию проще всего выполнять с помощью метода Where. Например, если требуется отфильтровать и вывести элементы массива, меньшие 5, то вот код:

a.Where(x -> x < 5).Println;

Если надо отфильтровать данные и записать результат в тот же массив, то используем преобразование к массиву методом ToArray:

a := a.Where(x -> x < 5).ToArray;

Бывает так, что после фильтрации надо вычислить какую-то характеристику отфильтрованных элементов – например, найти их сумму, среднее или минимум-максимум:

a.Where(x -> x > 10).Sum.Print; a.Where(x -> x in 2..8).Average.Print; a.Where(x -> x mod 2 = 0).Min.Print;

С помощью

a.Where(x -> x in 2..8).Count

можно вычислять количество элементов, удовлетворяющих некоторому условию. Однако то же можно сделать с помощью метода Count с параметром (см. следующий пункт).

Кроме того, отфильтрованные элементы можно далее преобразовывать методом Select, используя цепочку методов:

a.Where(x -> x in 2..8).Select(x -> x + 10).Println;

Задачи на поиск количества элементов, удовлетворяющих некоторому условию

Если надо найти количество опеределенных элементов, то используется метод CountOf:

a.CountOf(3) – количество троек в массиве

Если же надо найти количество элементов, удовлетворяющих условию, то используется метод Count с параметром:

a.Count(x -> x in 2..8)

Задачи на использование срезов

Срез массива – это набор элементов массива, расположенных последовательно или с некоторым шагом.

Если есть массив из 10 элементов

var a := Arr(1..10);

то a[1:5] – это срез элементов массива с индексами от 1 до 4

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

a[:5] – первые 5 элементов

a[5:] – срез с элемента с индексом 5 до конца

Кроме этого, есть срезы с шагом:

a[::2] – все элементы с четными индексами

a[1::2] – все элементы с нечетными индексами

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

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

a[::2].Sum – сумма элементов с четными индексами

a[1::2].Average – среднее элементов с нечетными индексами

a[:5].Min – минимальный среди первых 5 элементов

Можно комбинировать срезы и методы массивов:

a[:5].Where(x -> x mod 2 = 0) – отфильтровать четные элементы среди первых пяти элементов массива

Индексация с конца и срезы

В ряде задач может встречаться индексация элементов с конца:

a[^1] – это первый элемент с конца (последний)

a[^2] – это второй элемент с конца (предпоследний)

Индексация с конца может сочетаться со срезами, например,

a[:^1] – все элементы кроме последнего

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

a[1:^1].Sum – сумма всех элементов кроме нулевого и последнего