| Содержание | Предисловие | В

Глава 3

    В этой главе:


Массивы и списочные данные

Список и массив

Список это упорядоченные скалярные данные. Массив -- пере

Массивы могут иметь любое число элементов. Минимально возможный массив не имеет элементов вообще, тогда как максимально возможный может заполнять всю наличную память. Это еще одно подтверждение принятой в 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); # так-то лучше! @аfred

barney

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;

# как @х = qw(fred barney betty wilma); @who = @x[2,3]

Значения индексов в этих примерах литеральные целые, но индекс может быть и любым выражением, которое возвращает число, использу

@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

* Это перевод английского термина slice, использованный в данной книге. Более точно суть операции можно было бы выразить

Присваивание значение элементу, находящемуся за пределами текущего массива, автоматически расширяет его (с присваиванием всем промежуточным значениям, если таковые имеются, значения

@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 получает значение "Now for a bb ccc 123 here!"

Можно также выбрать часть массива с помощью среза:

@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.




|     Назад     |  

| Содержание | Предисловие | В



Сайт создан в системе uCoz