ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
МассивыВведениеЕсли попросить вас перечислить содержимое своих карманов, назвать имена трех последних президентов или объяснить, как пройти к нужному месту, в любом случае получится синеок: вы называете объекты один за другим в определенном порядке. Списки являются частью нашего мировоззрения. Мощные примитивы Perl для работы со списками и массивами помогают преобразовать мировоззрение в программный код. Термины список (list) и массив (array) трактуются в этой главе в соответствии с канонами Perl. Например, ("Reagan", "Bush", "Clinton") - это список трех последних американских президентов. Чтобы сохранить его в переменной, воспользуйтесь л/ассмоол<: ©presidents = ("Reagan", "Bush", "Clinton"). Каждый из этих терминов относится к упорядоченной совокупности скалярных величин; отличие состоит в том, что массив представляет собой именованную переменную, размер которой можно непосредственно изменить, а список является скорее отвлеченным понятием. Можно рассматривать массив как переменную, а список - как содержащиеся в пей значения. Отличие может показаться надуманным, но операции, изменяющие размер этой совокупности (например, push или pop), работают с массивом, а не списком. Нечто похожее происходит с $а и 4: в программе можно написать $а++, no ne 4++. Аналогично, рор(@а) - допустимо, а рор(1, 2, 3) - пет. Главное - помнить, что списки и массивы в Perl представляют собой упорядоченные совокупности скалярных величин. Операторы и функции, работающие со списками и массивами, обеспечивают более быстрый или удобный доступ к элементам по сравнению с ручным извлечением. Поскольку размер массива изменяется не так уж часто, термины "массив" и "список" обычно можно считать синонимами. Вложенные списки не создаются простым вложением скобок. В Perl следующие строки эквивалентны:@nested = ("this", "that", "the", "order"); @nested = ("this", "that", ("the", "order")); Почему Perl не поддерживает вложенные списки напрямую? Отчасти по историческим причинам, по также и потому, что это позволяет многим операциям (типа print или sort) работать со списками произвольной /тины и произвольного содержания. Что делать, если требуется более сложная структура данных - например, массив массивов или массив хэшей? Вспомните, что скалярные переменные могут хранить не только числа или строки, но и ссылки. Сложные (многоуровневые) структуры данных в Perl всегда образуются с помощью ссылок. Следовательно, "двумерные массивы" или "массивы массивов" в действительности реализуются как массив ссылок на массивы - по аналогии с двумерными массивами С, которые могут представлять собой массивы указателей на массивы. Для большинства рецептов этой главы содержимое массивов несущественно Например, проблема слияния двух массивов решается одинаково для массивол строк, чисел или ссылок. Решения некоторых проблем, связанных с содержимым массивов, приведены в главе 11 "Ссылки и записи". Рецепты этой главы ограничиваются обычными массивами. Давайте введем еще несколько терминов. Скалярные величины, входящие в массив или список, называются элементами. Для обращения к элементу используется его позиция, или индекс. Индексация в Perl начинается с 0, поэтому в следующем списке: @tune = ("The", "Star-Spangled", "Banner" ); элемент "The" находится в первой позиции, но для обращения к нему используется индекс 0: $tune[0]. Это объясняется как извращенностью компьютерной логики, где нумерация обычно начинается с 0, так и извращенностью разработчиков языка, которые выбрали 0 как смещение внутри массива, а не порядковый номер элемента. 4.1. Определение списка в программеПроблемаТребуется включить в программу список - например, при инициализации массива.РешениеПеречислите элементы, разделяя их запятыми:@а = ("quick", "brown", "fox"); При большом количестве однословных элементов воспользуйтесь оператором qw(): @a = qw(Why are you teasing me?); При большом количестве многословных элементов создайте встроенный документ
и последовательно извлекайте из него строки:
КомментарийНаиболее распространен первый способ - в основном из-за того, что в виде литералов в программе инициализируются лишь небольшие массивы. Инициализация большого массива загромождает программу и усложняет ее чтение, поэтому такие массивы либо инициализируются в отдельном библиотечном файле (см. главу 12 "Пакеты, библиотеки и модули"), либо просто читаются из файла данных:@bigarray = (); open(DATA, "< mydatafile") or die "Couldn't read from datafile: $!\n"; while () { chomp; push(@bigarray, $_); } Во втором способе используется оператор qw. Наряду с q(), qq() и qx() он предназначен для определения строковых величин в программе. Оператор q() интерпретируется но правилам для апострофов, поэтому следующие две строки эквивалентны: $banner = 'The mines of Moria': $banner = q(The mines of Moria): Оператор qq() интерпретируется по правилам для кавычек: $name = "Gandalf"; $banne'r = "Speak, $name, and enter!"; $banner = qq(Speak, $name, and welcome!); А оператор qx() интерпретируется почти так же, как и обратные апострофы, - то есть выполняет команду с интерполяцией переменных и служебными символами \ через командный интерпретатор. В обратных апострофах интерполяцию отменить нельзя, а в qx - можно. Чтобы отказаться от расширения переменных Perl, используйте в qx ограничитель : $his_host = 'www.perl.com'; $host_info = 'nslookup $his_host'; # Переменная Perl расширяется $perl_info = qx(ps $$); # Значение $$o от Perl $shell_info = qx'ps $$'; # Значение $$ от интерпретатора Если операторы q(), qq() и qx() определяют одиночные строки, то qw() определяет список однословных строк. Строка-аргумент делится по пробелам без интерполяции переменных. Следующие строки эквивалентны: @banner = ('Costs', 'only', '$4.95'); ©banner = qw(Costs only $4.95); ©banner = split(' ', 'Costs only $4.95'); Во всех операторах определения строк, как и при поиске регулярных
выражений, разрешается выбор символа-ограничителя, включая парные скобки.
Допустимы все четыре тина скобок (угловые, квадратные, фигурные и круглые).
Следовательно, вы можете без опасении использовать любые скобки при условии,
что для открывающей скобки найдется закрывающая:
$sample = qw(The vertical bar (|) looks and behaves like a pipe.); Если ограничитель встречается в строке, а вы не хотите заменить его
другим, используйте префикс \:
!> Смотри также --------------------------------- Раздел "List Value Constructors" perldata(1) раздел "Quote and Quote-Like Operators" perlop(1); оператор s/// описан в реrlоg(1). 4.2. Вывод списков с запятымиПроблемаТребуется вывести список с неизвестным количеством элементов. Элементы разделяются занятыми, а перед последним элементом выводится слово and.РешениеСледующая функция возвращает строку, отформатированную требуемым образом:sub commify_series {
КомментарийПри выводе содержимое массива порой выглядит довольно странно:@аrrау = ("red", "yellow", "green");
I have redyellowgreen marbles. I have red yellow green marbles. На самом деле вам нужна строка "I have red, yellow, and green marbles". Приведенная выше функция генерирует строку именно в таком формате. Между двумя последними элементами списка вставляется "and". Если в списке больше двух элементов, все они разделяются запятыми. Пример 4.1 демонстрирует применение этой функции с одним дополнением: если хотя бы один элемент списка содержит запятую, в качестве разделителя используется точка с занятой. Пример 4.1. commify_series #!/usr/bin/perl -w
Результаты выглядят так: The list is just one thing.
Как видите, мы отвергаем порочную практику исключения последней занятой из списка, что нередко приводит к появлению двусмысленностей. > Смотри также ------------------------------- Описание функции grep в perlfunc(l); описание тернарного оператора выбора в perlop(1) Синтаксис вложенных списков рассматривается в рецепте 11.1. 4.3. Изменение размера массиваПроблемаТребуется увеличить или уменьшить размер массива. Допустим, у вас имеется массив работников, отсортированный но размерам оклада, и вы хотите ограничить его пятью самыми высокооплачиваемыми работниками. Другой пример - если окончательный размер массива точно известен, намного эффективнее выделить всю намять сразу вместо того, чтобы увеличивать массив постепенно, добавляя элементы в конец.РешениеПрисвойте значение $#ARRAY:ti Увеличить или уменьшить (SARRAY $#ARRAY = $NEW_LAST_ELEMENT_INDEX_NUMBER Присваивание элементу, находящемуся за концом массива, автоматически увеличивает массив: $ARRAY[$NEW_LAST_ELEMENT_INDEX_NUMBER] = $VALUE: Комментарий$"ARRAY - последний допустимый индекс массива OARRAY. Если ему присваивается значение меньше текущего, массив уменьшается. Отсеченные элементы безвозвратно теряются. Если присвоенное значение больше текущего, массив увеличивается. Новые элементы получают неопределенное значение. Однако $#ARRAY не следует путать с @ARRAY. $#ARRAY представляет собой последний допустимый индекс массива, a @ARRAY (в скалярном контексте, то есть в числовой интерпретации) - количество элементов. $#ARRAY на единицу меньше ©ARRAY, поскольку нумерация индексов начинается с 0. В следующем фрагменте использованы оба варианта:sub what_about_that_array {
Результат:
Элемент с индексом 3 пропал при уменьшении массива. Если бы программа
запускалась с ключом -w, Per! также выдал бы предупреждение об использовании
неинициализированной величины, поскольку значение $реор1е[3] не определено.
В следующем примере:
результат выглядит так:
> Смотри также -------------------------------- Описание $#ARRAY в perldata(1).
|