Поиск

Работа с массивами

Теперь, после знакомства с основными правилами построения массивов, пришло время изучить несколько полезных методов работы с ними.

Поэлементная работа с массивом

На 3-м занятии, "Управление процессом выполнения программы", были рассмотрены циклы while, for и некоторые другие конструкции управления течением программы. Многие задачи, выполнение которых требует использования массивов, связаны с поэлементной обработкой массива, называемой итерацией. Один из способов организации итерации — использование цикла for, например:

В первой строке инициализируется массив названий различных сортов мороженого. Для простоты кода использован оператор qw. Если бы в списке были названия, состоящие из нескольких слов, например Крем-брюле, пришлось бы использовать синтаксис с одинарными кавычками. Во второй строке выполняется основная часть работы- Счетчик $index инициализируется значением 0 и циклически увеличивается на единицу, пока не будет достигнуто значение §flavors. В данном случае ^flavors находится в скалярном контексте и имеет значение 5 — количество элементов массива.

Не правда ли, что для такой простой задачи, как перебор элементов массива, нужно выполнить большое количество работы? Наверняка в Perl должны быть предусмотрены средства, позволяющие упростить громоздкий код. Данный случай — не исключение. В Perl имеется, еще не рассмотренный нами, оператор цикла foreach. Оператор foreach устанавливает индексную переменную, называемую итератором, принимающую в цикле значение каждого элемента списка. Рассмотрим следующий пример:

Здесь переменная $сопе последовательно принимает значение каждого элемента массива Иlavors. Как только $сопе принимает значение очередного элемента массива Иlavors, выполняется тело цикла, выводящее сообщение с этим элементом. Не забывайте, что в цикле foreach итератор не просто принимает значения всех элементов списка. Фактически итератор здесь используется как указатель, поэтому модификация переменной $сопе в теле цикла приводит к модификации соответствующих элементов массива gflavors. Вот пример:

Во второй строке происходит модификация переменной $flavor — к ее значению добавляется слово мороженое. В третьей строке выводится фраза "Я люблю шоколадное мороженое", а затем подобные строки печатаются и для остальных сортов мороженого. После окончания цикла окажется, что к каждому элементу массива @f lavors добавлено слово мороженое.

В Perl служебные слова foreach и for— синонимы. Любое из них можно использовать вместо другого. В этой книге для ясности оператор foreachf) используется для итерации в массиве, а оператор for() — для обычных циклов, о которых шла речь на 3-м занятии, "Управление процессом выполнения программы". Имейте в виду, что эти операторы взаимозаменяемы.
Взаимные преобразования массивов и скаляров

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

@words=split(//, "В лесу родилась елочка");

После выполнения этого кода массив Swords будет содержать слова В, лесу, родилась и елочка без пробелов. Если исходная строка не определена, используется значение переменной $_. Если функция split вызывается без параметров, то выполняется разбиение на слова переменной $_. При этом в качестве символа-разделителя используется пробел. Существует также специальный шаблон разбиения " (нулевой шаблон), разделяющий скаляр на индивидуальные символы, как показано ниже:

В данном примере с терминала считывается отдельная строка и помещается в переменную $_. Следующая строка кода разбивает переменную $_ на отдельные символы. При этом используется нулевой шаблон. В результате функция split возвращает список всех символов, находящихся в переменной $_. Этот список присваивается списку, расположенному слева от оператора присваивания. Первый элемент слиска присваивается переменной $firstchar, а остальные элементы отбрасываются.

Используемые в операторе split шаблоны называются регулярными выражениями. Регулярные выражения — это довольно сложная тема, и мы вернемся к ней на 6-м занятии, "Поиск по шаблону". А пока для примеров мы будем использовать простые шаблоны, такие как пробелы, двоеточия и т.п. После того как вы познакомитесь с регулярными выражениями, я приведу примеры использования более сложных шаблонов для разделения скаляров с помощью оператора split.

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

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

Кроме разбиения, существует и обратная операция — слияние массивов и образование скаляров. Для этой цели в Perl предусмотрена функция join. Ей передается строка-разделитель и список элементов, которые нужно объединить. Вот пример:

Snumber=join(',', (1.. 10));

Здесь переменной $number присваивается строка 1,2,3,4,5,6,7,8,9,10. Вы можете использовать функции split и join для разделения и объединения строк, причем возвращаемое значение одной функции может поступать на вход другой:

В этом примере переменная $message преобразуется в список с помощью функции split. Этот список поступает на вход функции join и заново преобразуется в строку, но уже с дефисами. В результате выполнения этого кода будет выведено следующее сообщение:

Строка "Тут был Вася" состоит из: Т-у-т- -б-ы-л- -В-а-с-я

Упорядочивание элементов массива

Иногда требуется изменить порядок следования элементов в массиве. Например, программа на Perl должна прочитать из файла список пользователей, отсортировать их по алфавиту и распечатать. Для сортировки в Perl предусмотрена функция sort, которой в качестве аргумента передается список. Функция возвращает другой список, отсортированный по алфавиту. Исходный массив при этом не модифицируется. Вот пример:

После выполнения этого кода будет выведена строка: Буш Картер Клинтон Никсон Рейган Форд. Имейте в виду, что установленный по умолчанию порядок сортировки использует значения кодов ASCII. Это означает, что символы верхнего регистра имеют преимущество перед символами нижнего регистра. Числа при этом сортируются совсем не так, как вы могли бы ожидать. Они сортируются не по значению. Например, 11 идет после 100. Для сортировки по значению необходимо использовать порядок, отличный от заданного по умолчанию.

Функция sort позволяет выполнять сортировку в нужном вам порядке. Для этого ей в качестве первого параметра необходимо передать код или имя подпрограммы. Внутри блока или подпрограммы используются две переменные $а и $Ь, которые соответствуют двум элементам списка. Задача блока возвратить -1, 0 или 1, если $а меньше $Ь, $а равно $Ь или $а больше $Ь соответственно. Ниже приведен один из способов сортировки чисел. В массиве ¥irambers содержатся числовые значения, которые нужно отсортировать.

Этот пример, конечно же, будет сортировать числа, но его код выглядит слишком сложно для такой простой задачи. Как и следовало ожидать, в Perl есть замена такой сложной конструкции — специальный оператор, который в шутку называют "космическим кораблем" <=>. Этот оператор получил свое название из-за того, что он напоминает летающую тарелку (вид сбоку). Он возвращает -1, если левый операнд меньше правого, 0 — если операнды равны, 1 ~если левый операнд больше правого:

@sorted=sort { $a<=>$b;> @numbers;

Этот код компактнее, проще и легче читается. Оператор "космический корабль" можно использовать лишь для сравнения числовых значений.

Для сравнения строк используется оператор сшр, работающий подобным образом. Вы можете использовать гораздо более изощренный критерий сортировки, реализовав его в виде сложной подпрограммы сортировки. Примеры такой сортировки можно посмотреть в разделе 4 Perl FAQ.

И последняя функция, которую мы рассмотрим на этом занятии, — reverse. Она очень простая. В скалярном контексте в качестве параметра ей передается скаляр. Функция обращает порядок следования символов и возвращает полученную строку. Например, reverse("Perl")в скалярном контексте возвращает lreP. В контексте списка функция reverse возвращает список, элементы которого расположены в обратном порядке:

В этом примере вначале выполняется функция sort, которая сортирует список {Не, будем, прогибаться, под, изменчивый, мир). Этот список перестраивается в обратном порядке с помощью функции reverse и передается в качестве параметра функции join для объединения в строку. В качестве разделителей используются пробелы. Результат — прогибаться под мир изменчивый будем Не. Правда, трудно не согласиться с этим утверждением?