Пятница, 24.11.2017, 10:26
Приветствую Вас Гость | RSS
Главная | Лекции | Регистрация | Вход
Меню сайта
Форма входа
Логин:
Пароль:
Категории раздела
Лекция [24]
Мини-чат
100
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 2
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Программирование Perl
    Главная » Статьи » Лекция » Лекция

    Лекция 5.3: Списки и массивы

    Функции работы с массивами

    Для работы с таким популярным типом данных, как массивы, в Perl существует много удобных функций. Когда требуется организовать обработку списка, поочередно извлекая из него элементы, начиная с первого, применяется встроенная функцияshift. Она удаляет из массива первый элемент, возвращая его значение. Когда shift применяется к пустому списку, она возвращает неопределенное значение:

    $first = shift @array; # извлечь первый элемент в $first
    # синоним: ($first, @array) = @array;

    С помощью этой функции можно организовать цикл обработки массива, который закончится после извлечения из него последнего элемента, например:

    while (my $first = shift @array) { # пока @array не опустеет
     print "Обработан элемент $first.";
     print "Осталось ", scalar @array, " элементов\n";
    }

    Обратите внимание, что для вывода текущего размера массива нужно использовать scalar @array потому, что иначе printвоспримет @array как список для печати и выведет значения массива. Существует противоположная shift функцияunshift, которая вставляет свои аргументы в массив перед первым элементом, сдвигая существующие элементы вправо.

    unshift @array, $e1,$e2,$e3; # вставить значения в начало 
    # синоним: @array = ($e1,$e2,$e3, @array);

    С помощью массива можно организовать стек, данные в котором обрабатываются по алгоритму LIFO ("last in, first out", "последним пришел - первым ушел"). Для добавления данных в стек применяется операция push, которая добавляет элементы в конец массива:

    push @stack, $new; # добавить элемент в конец массива 
    # синоним: @stack = (@stack, $new);

    Для извлечения одного значения из стека служит встроенная функция pop, которая удаляет последний элемент массива, возвращая его значение:

    $last = pop @stack; # изъять последний элемент массива

    При помощи комбинации функций push и shift можно организовать список, реализующий очередь данных, у которой элементы добавляются в конец, а извлекаются из начала (в соответствии с алгоритмом FIFO, "first in, first out", "первым пришел - первым ушел").

    Для удаления или замены подсписка в массиве можно использовать функцию splice, которая удаляет идущие подряд элементы массива, заданные индексом первого элемента и количеством удаляемых элементов, и заменяет их новым списком (если он указан), возвращая список удаленных элементов.

    @array = (1..7); # исходный массив
    $offset = 2; $size = 4; # смещение и размер удаляемого списка
    @deleted = splice @array, $offset, $size, qw(новый список);
    # в @array теперь (1, 2, 'новый', 'список', 7)
    # в @deleted попали 4 удаленных элемента (3, 4, 5, 6)

    Если список для вставки не указан, то подсписок от элемента с индексом $offset в количестве $size элементов просто удаляется.

    Операция сортировки списка выполняется встроенной функцией sort, которая, не изменяя своего аргумента, возвращаетсписок, отсортированный по возрастанию строковых значений элементов исходного списка. Поясним на примере:

    @unsorted = (12, 1, 128, 2, 25, 3, 400, 53);
    @sorted = sort @unsorted;
    # в @sorted будет (1, 12, 128, 2, 25, 3, 400, 53)

    Если нужно упорядочить список другим образом, то нужно в качестве первого аргумента функции указать блок, выполняющий сравнение двух элементов сортируемого списка и возвращающий значения -1, 0, 1 - они означают, что первый элемент меньше, равен или больше второго. При сравнении чисел это проще всего сделать с помощью операции <=>, например:

    @sorted = sort {$a <=> $b } @unsorted;
    # в @sorted будет (1, 2, 3, 12, 25, 53, 128, 400)

    В блоке сравнения переменные $a и $b содержат значения двух текущих сравниваемых элементов. Для выполнениясортировки по убыванию достаточно поменять переменные местами {$b <=> $a }. Помните, что для сортировки в обратном порядке строковых значений нужно применить операцию сравнения строк {$b cmp $a }. Вместо блока можно вызвать пользовательскую подпрограмму, выполняющую сколь угодно сложные сравнения элементов сортируемого списка.

    Перестановку всех элементов списка в обратном порядке выполняет встроенная функция reverse, возвращающаяинвертированный список, не меняя исходного:

    @array = qw(Do What I Mean); # исходный список
    @backwards = reverse @array; # остается неизменным
    # в @backwards будет ('Mean', 'I', 'What', 'Do')

    Вложенный вызов функций позволяет сначала отсортировать список, а потом переставить элементы в обратном порядке:

    @backwards = reverse(sort(@array));
    # в @backwards будет ('What', 'Mean', 'I', 'Do')

    Обратите внимание, что во всех приведенных примерах по желанию программиста аргументы функций можно указывать в круглых скобках, но делать это не обязательно. Имея в своем распоряжении мощные примитивы для работы с массивами, подобныеreverse или splice, программист может легко решать весьма нетривиальные задачи. Это подтверждает короткая программана Perl, выполняющая циклический сдвиг массива тремя вызовами функции reverse:

    my @array = qw/Н А Ч А Л О К О Н Е Ц/; # исходный массив
    my $i = 3; # сдвиг массива ВЛЕВО на 3 элемента 
    my $n = @array; # число элементов массива 
     # алгоритм сдвига Кена Томпсона (1971)
    @array[0 ..$i-1] = reverse @array[0 .. $i-1]; 
    @array[$i .. $n-1] = reverse @array[$i .. $n-1]; 
    @array[0 .. $n-1] = reverse @array[0 .. $n-1]; 
    print "@array\n"; # результат: А Л О К О Н Е Ц Н А Ч

    Функция map позволяет выполнить действия над всеми элементами массива, поэтому ее нередко используют вместо цикла. У этой функции есть две формы вызова:

    @result = map ВЫРАЖЕНИЕ, СПИСОК
    @result = map БЛОК СПИСОК

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

    @result = map $_*10, (11, 32, 55); # работа со списком
    # в @result будет (110, 320, 550)

    При работе map специальная переменная $_ локально устанавливается как синоним текущего элемента списка, поэтому изменение переменной $_ приводит к изменению соответствующего элемента массива. Таким способом можно изменять значения элементов массива. В этом примере воспользуемся блоком, куда поместим операторы вычисления нового значения (если значение элемента больше 20, оно будет удесятеряться):

    @array = (11, 32, 55); # исходный массив
    @result = map {if ($_ > 20) {$_*=10;} else {$_;} } @array;
    # в @result будет (11, 320, 550)

    Список можно преобразовать в строку с помощью встроенной функции join, которая преобразует каждый элемент списка к строке, объединяет отдельные элементы списка в одну строку, вставляя между элементами указанный разделитель, и возвращает полученную строку в качестве результата. Например:

    @array = (5..10); # объединяемый список
    $delimiter = ':'; # разделитель элементов списка в строке
    $string = join $delimiter, @array; # объединение в строку
    # теперь $string содержит '5:6:7:8:9:10'

    Обратную операцию разделения строки по образцу на список строк выполняет встроенная функция split. Она разделяет строку по указанному разделителю и возвращает список составляющих строк. Можно ограничить число разделяемых подстрок, тогда строка будет разделена не более, чем на это число элементов. Например:

    $string = '5:6:7:8:9:10'; # исходная строка
    $delimiter = ':'; # разделитель подстрок
    $limit = 3; # число элементов
    @strings = split $delimiter, $string, $limit; # разделение
    # в @strings содержится ('5', '6', '7:8:9:10')

    Функция split имеет гораздо больше возможностей, о которых будет сказано в лекции, посвященной регулярным выражениям. Подробно познакомиться с которыми можно из системной документации с помощью утилиты perldoc (после флага -fуказывается имя искомой функции):

    perldoc -f split

    Пользовательские функции и процедуры, как встроенные функции, тоже могут обрабатывать списки: принимать списки параметров и возвращать список значений. Об этом будет подробнее рассказано в лекции 12.

    Операции в скалярном и списочном контекстах

    Рассмотренные ранее операции могут вести себя иначе, если они применяются не в скалярном, а в списочном контексте. Так, операция повторения (репликации), чаще всего применяемая к строкам, может также использоваться и для многократного повторения значений списка. Обратите внимание, что она работает именно со списками, поэтому если необходимо размножить значения массива, то его следует поместить в списочный литерал. Например:

    @two = ('A', 'B') x 2; # будет: ('A', 'B', 'A', 'B')
    @three = (@one) x 3; # в @three трижды повторится @one

    С помощью операции повторения можно присвоить одинаковые значения всем элементам массива, например, сделать их неопределенными. Таким образом результат функции undef() можно повторить по числу элементов массива:

    @array = (undef()) x @array; # или (undef) x scalar(@array)

    При необходимости ввести данные в массив можно воспользоваться упомянутой ранее операцией ввода строк <>, читающей строки из входного потока. В скалярном контексте операция "кристалл" считывает одну строку в переменную. Вот так можно в диалоге ввести значения в массив из пяти строк:

    for (@stdin = (), $n = 0; $n < 5; $n++) {
     print 'Введите значение N ', $n+1, ':';
     $stdin[$n] = <>; # считать строку в $n-й элемент массива
    }

    В списочном контексте "кристалл" читает в массив за одну операцию все строки файла. Например, так можно заполнить массивданными, вводимыми с консоли:

    print "Введите значения - по одному в строке.",
     "Для окончания ввода нажмите Ctrl-Z (или Ctrl-D).\n";
    @stdin = <>; # считать все строки и поместить их в массив
    print "Вы ввели ", scalar @stdin, " значений.\n";

    Операция <> вводит строки полностью, включая завершающий символ перевода строки, который часто не нужен при дальнейшей обработке. Функция chomp удаляет символы перевода строки в конце строки (в скалярном контексте) или в конце каждого элемента списка (в списочном контексте) и возвращает общее число удаленных символов.

    chomp @stdin; # убрать \n в конце всех элементов массива
    $n_count = chomp $string; # убрать \n в конце строки

    Похожая функция chop отсекает любой последний символ у строки (в скалярном контексте) или у каждого элемента списка (в списочном контексте) и возвращает последний отсеченный символ.

    $last_char = chop $string; # отсечь последний символ строки 
    chop @array; # отсечь последний символ в элементах массива

    Если нужно избавиться только от символов перевода строки, то применение функции chomp более безопасно, поскольку она никогда не удаляет значащие символы в конце строки.

    Специальные массивы

    При выполнении Perl-программы ей доступны значения специальных массивов, в которых хранится полезная служебнаяинформация. Вот некоторые из специальных массивов:

    @ARGV аргументы командной строки для выполняемой программы
    @INC список каталогов для поиска внешних Perl-программ
    @_ массив параметров для подпрограмм или буфер для split

    Рассмотренные в этой лекции материалы по работе со списками и массивами предоставляют программисту мощные и выразительные средства эффективной обработки больших объемов данных. Обобщением идеи массивов стали ассоциативные массивы, которые будут рассмотрены в следующей лекции.

    Категория: Лекция | Добавил: mazay (06.02.2014)
    Просмотров: 74 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Создать бесплатный сайт с uCozCopyright MyCorp © 2017