| Содержание | Предисловие | В |
Глава 3В этой главе:
Литеральное представление Переменные Операции над массивами и функции обработки массивов Скалярный и списочный контексты <STDIN> как массив Интерполяция массивов Упражнения Массивы и списочные данныеСписок и массив Список — это упорядоченные скалярные данные. Массив -- переМассивы могут иметь любое число элементов. Минимально возможный массив не имеет элементов вообще, тогда как максимально возможный может заполнять всю наличную память. Это еще одно подтверждение принятой в PerlЛитеральное представление Списочный литерал (способ представления значения списка в программе) состоит из значений, отделенных друг от друга запятыми и заключенными в круглые скобки. Эти значения образуют элемен (1,2,3) # массив из трех значений 1, 2 и 3 ("fred",4.5)Элементы списка не обязательно должны быть константами. Это могут быть выражения, которые вычисляются при каждом использовании литерала. Например: ($а, 17; # два значения: текущее значение переменной $а и 17 ($b+$c,$d+$e) #Пустой список (список, не содержащий элементов) представляется пустой парой круглых скобок: () # пустой список (нуль элементов)Элемент списочного литерала может включать операцию конструктора списка. Это два скалярных значения, разделенных двумя точками. Данная операция создает список значений, начиная с левого (1 .. 5) # то же самое, что (1, 2, 3, 4, 5)(1.2 .. 5.2) # то же самое, что (1.2, 2.2, 3.2, 4.2, 5.2)(2 .. 6,10,12) # тоже самое, что (2,3,4,5,6,10,12)($а .. $b) # диапазон, заданный текущими значениями переменных $а и $ЬЕсли правый скаляр меньше левого, то список будет пустым, так как в обратном направлении отсчет вести нельзя. Если последнее значение не соответствует целому числу шагов, то список заканчиваетс (1.3 .. 6.1) # то же самое, что (1.3,2.3,3.3,4.3,5.3)Списочные литералы с множеством коротких текстовых строк со всеми этими кавычками и запятыми выглядят не очень привлекательно: @а = ("fred","barney","betty","wilma"); # уф-ф!Поэтому предусмотрена функция заключения в кавычки, которая создает список из разделенных пробелами слов, заключенных в круглые скобки*: @а = qw(fred barney betty wilma); # так-то лучше! @аfredbarney betty wilma ); # то же самоеОдно из возможных применений списочного литерала — в качестве аргумента функции print,print("The answer is ",$a,"\n"); # трехэлементный списочный литералЭтот оператор выводит на экран слова The answer is, затем пробел, значение переменной $а и символ новой строки. Другие способы исп* Как и в функциях сопоставления с образцом, о которых мы узнаем позже, в качестве разделителя здесь вместо круглых скобок можно использовать любой символ, не относящийсяПеременные Переменная-массив содержит одно значение в виде списка (нуль или более скалярных значений). Имена переменных-массивов похожи на имена скалярных переменных. Единственное отличие состоит @fred # массив-переменная @fred @A_Very_Long_Array_Variable_Name @A_Very_Long_Array_VariaОтметим здесь, что переменная-массив @fred не имеет никакого отношения к скалярной переменной $fred.Выражение может ссылаться на переменные-массивы в целом, а также проверять и изменять отдельные элементы таких массивов. Операции над массивами и функции обработки массивов Операции над массивами и функции обработки массивов манипулируют целыми массивами. Некоторые из них возвращают список, который затем можно использовать как значение в другой функции обр Присваивание Вероятно, самая важная операция, проводимая над массивами -— операция присваивания, посредством которой переменной-массиву@fred = (1,2,3); # массив fred получает трехэлементноеЕсли переменной-массиву присваивается скалярное значение, оно становится единственным элементом этого массива: @huh =1; #1 автоматически становится списком (1)Имена переменных-массивов могут входить в списочный литерал. При вычислении значений такого списка Perl заменяет имена массивов те@fred = qw(one two); @barney = (4,5,@fred,6,7) ; # @barney превращается в (4,5,"one","two",6,7) @barney = (8,@barney); # в начале списка элемен# и "last" в конце. Qbarney = (@barney,"last") ; # @barney превраща# (8,4,5,"one","two",6,7,"last") Отметим, что вставленные подобным образом элементы массива находятся на том же уровне иерархии, что и остальная часть литерала: список не может содержать другой список в качестве элемента*. Если списочный литерал содержит только ссылки на переменные (а не выражения), то этот литерал также можно рассматривать как переменную. Другими словами, такой списочный литерал можно использовать в левой части операции присваивания. Каж ($а,$Ь,$с) = (1,2,3); # присвоить 1 переменной $а, 2 —# 3 — переменной $с ($a,$b) = ($b,$a); # поменять местами $а и $Ь ($d,@fred) = ($a,$b,$c)# в переменную $е. В результате @fred = ($с),# а $е = $ЬЕсли число присваиваемых элементов не соответствует числу переменных, то лишние значения (стоящие справа от знака равенства) просто отбрасываются, а все лишние переменные (слева от знака равенс Переменная-массив, входящая в литеральный список, должна стоять в нем последней, потому что переменные-массивы очень "прожорливы" и поглощают все оставшиеся значения. (Конечно, после нее можно Если переменная-массив присваивается скалярной переменной, то присваиваемое число является размером массива, например: @fred = (4,5,6); # инициализация массива @fred $а = @fred; #Размер возвращается и в том случае, если имя переменной-массива используется там, где должно быть скалярное значение. (В разделе "Скалярный и списочный контексты" мы увидим, что это называется * Хотя ссылка на список и может быть элементом списка, на самом деле это не означает использование списка в качестве элемента другого списка. Впрочем, работает этомассива в скалярном контексте.) Например, чтобы получить число на единицу меньшее, чем размер массива, можно использовать @fred-l,$а = @fred; # переменной $а присваивается размер массиваПервое присваивание — скалярное, и массив @fred рассматривается какВ результате выполнения присваивания для массива мы получаем значение, представляющее собой список. Это позволяет делать "каскадиро-вание". Например: @fred = (Qbarney = (2,3,4)); # @fred и @barney получают значения (2,3,4) @fred = @barney = (2,3,4);Обращение к элементам массива До сих пор мы рассматривали массив в целом, добавляя и удаляя значения с помощью присваивания для массива. Многие полезные программы так и построены —Элементы массива нумеруются последовательными целыми числами с шагом 1, начиная с нуля*. Первый элемент массива @fred@fred = (7,8,9); $b = $fred[0]; # присвоить $Ь значение 7 (первый элемент массива @fred) $fred[0] = 5;Точно так же можно обращаться к другим элементам: $с = $fred[l]; # присвоить $с значение 8$fred[2]++; # инкрементировать третий элемент массива @fred$fred[l] +=4; # прибавить 4 ко второму элементу($fred[0],$fred[l]) = ($fred[l],$fred[0]) ; # * Значение индекса первого элемента можно изменить на что-нибудь другое (например, на "1"). Это, однако, повОбращение к списку элементов одного массива (как в последнем примере) называется срезом" и встречается достаточно часто, поэтому для него есть специальное обозначение. @fred[0,l] * то же, что и ($fred[0],$fred[l]) @fred[0,l] = @fred[l,0] # поменять местами первые два элеОбратите внимание: в этом срезе используется не $, а @. Это вызвано тем, что вы создаете переменную-массив (выбирая для этого частСрезы работают также с литеральными списками и вообще с любой функцией, которая возвращает список: @who = (qw(fred barney betty wilma))[2,31; # Значения индексов в этих примерах — литеральные целые, но индекс может быть и любым выражением, которое возвращает число, использу@fred ” (7,8,9) ; $а = 2;$b " $fred[$a); f как $fred[2], или 9$с = $fred[$a-l]; # $c получает значение $fred[l], или 8<($с) = (7.8,9)[$а-1]; # то же самое, но с помощью срезаТаким образом, обращение к массивам в Perl-программах может производиться так же, как во многих других языках программирования.Идея использования выражения в качестве индекса применима и к срезам. Следует помнить, однако, что индекс среза — список значений, поэтому выражение представляет собой выражSfred = (7,8,9); f как в предыдущем примере Bbarney =(2,1,0);Obackfred = @fred[@barney]; # то же, что и @fred[2,l,0], или ($fred[2],$fred[l],$fred[0]), илиЕсли обратиться к элементу, находящемуся за пределами массива (т.е. задав индекс меньше нуля или больше индекса последнего элемента), то возвращается значение undef.<@fred = (1,2,3) ; $barney = $fred[7]; # $barney теперь имеет значение undef* Присваивание значение элементу, находящемуся за пределами текущего массива, автоматически расширяет его (с присваиванием всем промежуточным значениям, если таковые имеются, значения @fred = (1,2,3); fred[3] = "hi"; # @fred теперь имеет значение (1,2,3,"hi") $fred[6] = "ho"; # @fred теперь имеет значение# (1,2,3,"hi",undef,undef,"ho") Присваивание значения элементу массива с индексом меньше нуля является грубой ошибкой, потому что происходит такое, скорее всего, из-за Очень Плохого Стиля Программирования. Для получения значения индекса последнего элемента массива @fred можно использовать операцию $#fred. Можно дажИспользование отрицательного индекса означает, что следует вести обратный отсчет от последнего элемента массива. Так, последний элемент массива можно получить, указав индекс -1.@fred = ("fred", "wilma", "pebbles", "dino"); print $fred(-l]; # выводит "dino" print $#fred; # выводит 3 print $fred[$#fred]; #Функции push и popОдним из распространенных вариантов использования массива является создание стека данных, где новые значения вводятся и удаляются с правой стороны списка. Эти операции применяются довол push(@mylist,$newvalue); # означает Omylist =• (@mylist,$newvalue) $oldvalue = pop($mylist); # удаляет последний эЕсли в функцию pop введен пустой список, она возвращает undef, не вФункция push также принимает список значений, подлежащих помещению в стек. Эти значения вводятся в конец списка. Например:@mylist = (1,2,3); push(@mylist,4,5,6) ; # @mylist = (1,2,3,4,5,6) Отметим, что первый аргумент должен быть именем переменной-масси-ва, потому что для литеральных списков функции push иФункции shift и unshiftФункции push и pop действуют в "правой" части списка (частиunshift(@fred,$a); # соответствует Bfred = ($a,@fred);unshift (@fred,$a,$b,$c); # соответствует @fred = ($а,$b,$c,@fred);$х = shift(@fred); # соответствует ($x,@fred) = @fred;# с реальными значениями @fred = (5,6,7) ;unshift(@fred,2,3,4); # @fred теперь имеет значение (2,3,4,5,6,7) $х = shift(@fred) ;# $х получает значение 2, @fred теперь имеет значение (3,4,5,6,7)Как и функция pop, функция shift, если в нее ввести пустую перемен-Функция reverseФункция reverse изменяет порядок следования элементов аргумента на противоположный и возвращает список-результат. Например@а = (7,8,9) ;@b = reverse(@a); t присваивает @Ь значение (9,8,7) @b == reverse (7,8,9); # делает то же самоеОбратите внимание: список-аргумент не изменяется, так как функция reverse работает с копией. Если вы хотите изменить порядок элеме@Ь = reverse (@b); t присвоить массиву @Ь его же значения,# но расположить его элементы в обратном порядке Функция sortФункция sort сортирует аргументы так, как будто это отдельные строки, в порядке возрастания их кодов A@х ° sort("small","medium","large") ;# @х получает значение "large", "medium", "small" @у = (1,2,4,8,16,32,64) ;@у = sort (@y); # @у получает значение 1, 16, 2, 32, 4, 64, 8Отметим, что сортировка чисел производится не по их числовым значениям, а по их строковым представлениям (1,16, 2, 32 и т.д.). ИзуФункция chompФункция chomp работает не только со скалярной переменной, но и с массивом. У каждого элемента массива удаляется последний@stuff = ("hello\n","world\n","happy days") ; chomp(@stuff); # Sstuff теперь имеет значение ("hello","world","happy day")Скалярный и списочный контексты Как видите, каждая операция и функция предназначена для работы с определенной комбинацией скаляров или списков и возвращает скаляр или список. Если операция или функция рассчитывает на Как правило, это особого значения не имеет, но иногда в разных контекстах можно получить совершенно разные результаты. Например, в списочном контексте @fred возвращает сСкалярное значение, используемое в списочном контексте, превращается в одноэлементный массив. <STDIN> как массивОдна из ранее изученных нами операций, которая в списочном контексте возвращает иное значение, чем в скалярном, — <stdin>.$а = <STDIN>; # читать стандартный ввод в списочном контекстеЕсли пользователь, выполняющий программу, введет три строки и нажмет [Ctrl+D]* (чтобы обозначить конец файла), массив будет состоя* В некоторых системах конец файла обозначается нажатием клавиш [Ctrl+Z], а в других эта комбинация служит дИнтерполяция массивов Как и скаляры, значения массивов могут интерполироваться в строку, заключенную в двойные кавычки. Каждый элемент массива заменяется его значением, например: Ofred = ("hello","dolly"); $у = 2;$х = "This is $fred[l]'s place"; # "This is dolly's place" $x = "This is $fred($y-l]'s place"; # ToОтметим, что индексное выражение вычисляется как обычное, как будто оно находится вне строки, т.е. оно предварительно не интерполируется. Если вы хотите поставить после простой ссылки на скалярную переменную литеральную левую квадратную скобку, нужно выделить эту скобку так, чтобы она не считалась частью массива: Ofred = ("hello","dolly"); # присвоить массиву @fred значение для проверки $fred = "right";# мы пытаемся сказать "this is right[1]" $х = "this is $fred[l]"; t неправильно,Аналогичным образом может интерполироваться список значений перемен-ной-массива. Самая простая интерполяция — интерполяция всего м@fred = ("а", "bb","ccc",1,2,3) ;$а11 = "Mow for Sfred here!";# $all Можно также выбрать часть массива с помощью среза: @fred = ("а","bb","ccc",1,2,3);$а11 = "Now for @fred[2,3] here!";# $all получает значение "Now for ccc 1 here!" $all = "Now for @fred[@fred[4,5]] here!"; ” то же самоеОпять-таки, если вы хотите поставить после ссылки на имя массива литеральную левую квадратную скобку, а не индексное выражение, можете использовать любой из описанных выше механизмов. Упражнения Ответы к упражнениям приведены в приложении А. 1. Напишите программу, которая читает список строковых значений, стоящих в отдельных строках, и выводит этот список в обратном порядке. Если вы читаете список на экране, то2. Напишите программу, которая читает число, затем список строковых значений (находящихся в отдельных строках), после чего выводит одну из строк списка в соответствии с указанным числом.3. Напишите программу, которая читает список строк, а затем выбирает и выводит на экран случайную строку из этого списка. Чтобы выбрать случайный элемент массиваsrand; (она инициализирует генератор случайных чисел), а затем используйте rand(@somearray) там, где требуется случайное значение, меньшее размера массива @ some-array. |
| Содержание | Предисловие | В |