"Язык программирования Perl" - читать интересную книгу автора (Шохирев Михаил Васильевич)Автор: Шохирев Михаил Васильевич Название: Язык программирования Perl Лекция 5. Списки и массивыВ этой лекции рассмотрены списки - один из основных типов данных в Perl. Представлять данные в виде списков и массивов - очень естественно для Perl-программистов. А богатые средства работы со списками, массивами и срезами массивов, приведенные в этой лекции, предоставляют разработчику широкие возможности по обработке данных. Цель лекции: познакомиться со списками и массивами, освоить возможности работы со списочными данными в Perl, включая встроенные функции и операции в списочном и скалярном контекстах. Помимо уже изученных скалярных данных, в Perl широко применяется другой тип данных - списки. Если скаляры представляют в программе единичные объекты реального мира, то списки, как и в жизни, позволяют представить набор объектов, однотипных или совершенно разных, которые для решаемой задачи удобно рассматривать как единое целое (например, "список работников", "перечень документов", "опись товаров" и так далее). В то же время, всегда можно обратиться к любому элементу списка и обработать хранящуюся в нем информацию нужным образом, при необходимости повторяя действия для каждого элемента массива. Итак, список - это упорядоченная последовательность отдельных скалярных данных в виде одного программного объекта. Способом представления значения списка в программе является списочный литерал, который записывается в виде последовательности значений, разделенных запятыми и заключенных в круглые скобки. Вот примеры списочных литералов:
Для записи списка текстовых строк, состоящих из одного слова, предусмотрена специальная форма списочного литерала, в которой после ключевого слова
Элементами списочного литерала могут быть не только строки и числа, но также скалярные переменные и выражения. Пустой список не содержит элементов и представляется списочным литералом без значений (одними круглыми скобками).
Списочный литерал может содержать операцию диапазона, которая записывается в виде двух скалярных значений, разделенных двумя точками:
В списочном контексте эта операция возвращает список значений. Возвращаемый список начинается со значения левого операнда, которое в цикле увеличивается на единицу, пока не будет достигнуто значение правого операнда. Приведем примеры:
Если операция диапазона применяется к строкам, то значения списка генерируются по правилам операции автоинкремента. С ее помощью удобно записывать различные списочные литералы:
Если списочный литерал состоит только из имен переменных, то он может стоять в левой части операции присваивания, в правой части которой будет список присваиваемых значений. Переменным, стоящим слева от знака "равно", последовательно присваиваются значения соответствующих элементов списка из правой части операции.
Если в списке слева от знака присваивания переменных больше, чем значений в списке в правой части, то оставшиеся переменные получают неопределенные значения:
Если в левой части присваивания переменных меньше, чем значений в правой, то лишние значения не используются.
Если в левой части присваивания стоит не список, а скалярная переменная, то устанавливается скалярный контекст, в котором литеральный список возвращает значение своего последнего элемента:
Значение списка может храниться в переменной, называемой массив. Перед именем переменной-массива стоит разыменовывающий префикс @ (напоминающий своим видом, что это array - "массив"). Одновременно с переменной-массивом в программе может существовать скалярная переменная с таким же именем, но с префиксом $, так как имена скаляров и массивов хранятся в разных таблицах имен (symbol tables).
Списочное значение помещается в массив с помощью операции присваивания. Присваивание выполняется по-разному в зависимости от контекста, который определяется левым операндом присваивания. Если в левой части присваивания стоит массив или список, то и в правой части ожидается список. Например:
Если в левой части присваивания стоит скалярная переменная, то устанавливается скалярный контекст и в правой части операции ожидается скалярное значение. Например, если попытаться присвоить скалярной переменной массив, то ее значением станет размер массива. Того же результата можно добиться, явно задав для массива скалярный контекст встроенной функцией
В зависимости от контекста, системная функция
В состав списочного литерала могут входить массивы и другие списочные литералы - тогда они заменяются списком своих значений. Но результирующий массив будет одномерным, так как вложенные списки в Perl не предусмотрены. Массивы массивов организуются с помощью ссылок, что будет изучено в лекции 11. Вот примеры такой инициализации массива:
С помощью списка можно легко добавить новые элементы в начало или в конец существующего массива:
Присваивая массив списочному литералу, можно извлечь начальные элементы из массива в скалярные переменные, поместив оставшиеся элементы в исходный массив:
Массив в левой части присваивания имеет смысл ставить только в конце списка, поскольку он поглощает все значения, и стоящие после него переменные получат неопределенные значения:
Элементы массива - это скалярные величины, доступ к которым происходит по их порядковому номеру (индексу). Поскольку элемент массива - это скаляр, то его обозначение состоит из разыменовывающего префикса $ перед именем массива, за которым в квадратных скобках стоит индекс. Индексы элементов массива задаются целыми числами, начиная с нуля. (Номер начального индекса массивов раньше мог задаваться значением специальной переменной $[, но сейчас эта возможность считается устаревшей, поэтому поступать так не рекомендуется.) Вот так выглядит в программе обращение к элементам массива:
Если требуется обращаться к элементам массива, начиная с последнего, то используются отрицательные значения индексов:
Индекс последнего элемента массива, который всегда на единицу меньше размера массива, можно узнать, указав специальный префикс $# перед именем массива:
Так, например, можно выбрать элемент массива с помощью встроенного генератора случайных чисел
В $#array можно присвоить новое значение последнего индекса, при этом размер массива изменится. Но такое действие обычно не требуется, так как массив при необходимости увеличивается автоматически. Размер массива в Perl не ограничивается, то есть массив может занимать всю отведенную программе память. В операции присваивания отдельные элементы массива рассматриваются как обычные скаляры. Ниже приведены примеры, по-разному выполняющие одно и то же присваивание элементам массива:
(Хотя более естественно для подобного присваивания воспользоваться срезом массива: Если попытаться присвоить значение элементу с индексом больше текущего размера массива, массив автоматически увеличивается до необходимой длины, а добавленные элементы получают неопределенное значение:
При попытке обратиться к элементу массива с несуществующим индексом будет возвращено неопределенное значение, но ошибки во время выполнения программы не возникнет.
При использовании в качестве индекса массива дробного числа будет взята его целая часть, то есть Часто требуется последовательно перебрать все элементы массива, от первого до последнего, для обработки или вывода их значений. Это можно сделать вполне традиционным образом, с помощью цикла
Perl предлагает для подобных действий более удобный способ с использованием цикла
Можно то же самое записать еще более кратко с помощью модификатора
Так что каждый Perl-программист выбирает свой способ перебора всех элементов массива в полном соответствии с лозунгом TIMTOWTDI. Обратите внимание, что значения элементов массива, будучи обычными скалярами, интерполируются в строках, заключенных в двойные кавычки. Целые массивы тоже интерполируются, если имя массива появляется в строке, обрамленной двойными кавычками. При этом значения элементов массива разделяются символом, хранящимся в специальной переменной $" (по умолчанию - пробелом). Вот еще один способ напечатать значения всех элементов массива, разделяя их двоеточиями:
С помощью индексов можно обращаться не только к элементам массива, но и к элементам списка, в том числе и литерального. Для этого после закрывающей скобки списка указывается значение индекса в квадратных скобках:
Обращение по индексу к элементу в списке констант приобретает смысл, если индекс динамически вычисляется при выполнении программы. Вот, например, один из способов преобразовать десятичное число в шестнадцатеричное:
Подобным же образом удобно обращаться к элементу списка, возвращаемого функцией. Например, так можно извлечь день месяца, зная, что у него 3-й индекс в результирующем списке функции
В Perl есть удобная форма обращения к нескольким элементам массива одновременно, называемая срезом массива. Срез (slice) - это набор элементов массива, заданный списком индексов этих элементов. Срез обозначается квадратными скобками после имени массива, в которых перечислены индексы элементов. Поскольку значение среза - это список, при записи среза перед именем массива сохраняется префикс @. Срез массива в частном случае может состоять из одного значения, заданного одним индексом. Вот примеры срезов массивов:
С помощью срезов удобно одновременно манипулировать значениями нескольких элементов, находящихся в любом месте массива:
Срезы могут применяться не только к массивам, но и к любым спискам, в том числе литеральным. Для работы с таким популярным типом данных, как массивы, в Perl существует много удобных функций. Когда требуется организовать обработку списка, поочередно извлекая из него элементы, начиная с первого, применяется встроенная функция
С помощью этой функции можно организовать цикл обработки массива, который закончится после извлечения из него последнего элемента, например:
Обратите внимание, что для вывода текущего размера массива нужно использовать
С помощью массива можно организовать стек, данные в котором обрабатываются по алгоритму LIFO ("last in, first out", "последним пришел - первым ушел"). Для добавления данных в стек применяется операция
Для извлечения одного значения из стека служит встроенная функция
При помощи комбинации функций Для удаления или замены подсписка в массиве можно использовать функцию
Если список для вставки не указан, то подсписок от элемента с индексом Операция сортировки списка выполняется встроенной функцией
Если нужно упорядочить список другим образом, то нужно в качестве первого аргумента функции указать блок, выполняющий сравнение двух элементов сортируемого списка и возвращающий значения -1, 0, 1 - они означают, что первый элемент меньше, равен или больше второго. При сравнении чисел это проще всего сделать с помощью операции
В блоке сравнения переменные Перестановку всех элементов списка в обратном порядке выполняет встроенная функция
Вложенный вызов функций позволяет сначала отсортировать список, а потом переставить элементы в обратном порядке:
Обратите внимание, что во всех приведенных примерах по желанию программиста аргументы функций можно указывать в круглых скобках, но делать это не обязательно. Имея в своем распоряжении мощные примитивы для работы с массивами, подобные
Функция map позволяет выполнить действия над всеми элементами массива, поэтому ее нередко используют вместо цикла. У этой функции есть две формы вызова:
Она вычисляет выражение или блок для каждого элемента списка и возвращает список результатов. С ее помощью, например, можно выполнить арифметическое действие над всеми элементами списка:
При работе map специальная переменная
Список можно преобразовать в строку с помощью встроенной функции
Обратную операцию разделения строки по образцу на список строк выполняет встроенная функция
Функция
Пользовательские функции и процедуры, как встроенные функции, тоже могут обрабатывать списки: принимать списки параметров и возвращать список значений. Об этом будет подробнее рассказано в лекции 12. Рассмотренные ранее операции могут вести себя иначе, если они применяются не в скалярном, а в списочном контексте. Так, операция повторения (репликации), чаще всего применяемая к строкам, может также использоваться и для многократного повторения значений списка. Обратите внимание, что она работает именно со списками, поэтому если необходимо размножить значения массива, то его следует поместить в списочный литерал. Например:
С помощью операции повторения можно присвоить одинаковые значения всем элементам массива, например, сделать их неопределенными. Таким образом результат функции
При необходимости ввести данные в массив можно воспользоваться упомянутой ранее операцией ввода строк lt;gt;, читающей строки из входного потока. В скалярном контексте операция "кристалл" считывает одну строку в переменную. Вот так можно в диалоге ввести значения в массив из пяти строк:
В списочном контексте "кристалл" читает в массив за одну операцию все строки файла. Например, так можно заполнить массив данными, вводимыми с консоли:
Операция
Похожая функция
Если нужно избавиться только от символов перевода строки, то применение функции При выполнении Perl-программы ей доступны значения специальных массивов, в которых хранится полезная служебная информация. Вот некоторые из специальных массивов:
Рассмотренные в этой лекции материалы по работе со списками и массивами предоставляют программисту мощные и выразительные средства эффективной обработки больших объемов данных. Обобщением идеи массивов стали ассоциативные массивы, которые будут рассмотрены в следующей лекции. |
|
|