Если у кого-то есть заявленная проблема, выполните следующие шаги в окне терминала:
Вот и все. Задача решена.
Любое время Вы хотите генерировать список, основывало другой список:
# Double all elements of a list
my @double = map { $_ * 2 } (1,2,3,4,5);
# @double = (2,4,6,8,10);
Так как списки легко преобразовываются попарно в хеши, если Вы хотите хеш-таблицу для объектов на основе конкретного атрибута:
# @user_objects is a list of objects having a unique_id() method
my %users = map { $_->unique_id() => $_ } @user_objects;
# %users = ( $id => $obj, $id => $obj, ...);
Это - инструмент действительно общего назначения, необходимо только начать использовать его для нахождения хорошего использования в приложениях.
Некоторые могли бы предпочесть подробный код цикличного выполнения в целях удобочитаемости, но лично, я нахожу map
более читаемый.
Как другие сказали, карта является самой полезной для преобразования списка. То, что не было упомянуто, является различием между картой и "эквивалентом" для цикла.
Одно различие - то, что для не работает хорошо на выражение, которое изменяет список его итерация. Один из них завершается, и другой не делает:
perl -e '@x=("x"); map { push @x, $_ } @x'
perl -e '@x=("x"); push @x, $_ for @x'
Другая небольшая разница - то, что контекст в блоке карты является контекстом списка, но для цикла передает пустой контекст.
Вы используете карту, чтобы преобразовать список и присвоить результаты другому списку, grep, чтобы отфильтровать список и присвоить результаты другому списку. "Другой" список может быть той же переменной как список, который Вы преобразовываете/фильтруете.
my @array = ( 1..5 );
@array = map { $_+5 } @array;
print "@array\n";
@array = grep { $_ < 7 } @array;
print "@array\n";
Как другие сказали, карта создает списки из списков. Думайте об "отображении" содержания одного списка в другого. Вот некоторый код из программы CGI для взятия списка доступных чисел и гиперссылок печати к заявкам на патент:
my @patents = ('7,120,721', '6,809,505', '7,194,673');
print join(", ", map { "<a href=\"http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL&p=1&u=/netahtml/srchnum.htm&r=0&f=S&l=50&TERM1=$_\">$_</a>" } @patents);
Это используется каждый раз, когда требуется создать новый список из существующего списка.
, Например, Вы могли отобразить функцию парсинга в списке строк для преобразования их в целые числа.
Это позволяет Вам преобразовывать список как выражение, а не в операторах. Вообразите хеш солдат определенным как так:
{ name => 'John Smith'
, rank => 'Lieutenant'
, serial_number => '382-293937-20'
};
затем можно воздействовать на список имен отдельно.
Например,
map { $_->{name} } values %soldiers
выражение. Это может пойти куда угодно, выражение позволяется - кроме Вас, не может присвоить ему.
${[ sort map { $_->{name} } values %soldiers ]}[-1]
индексирует массив, беря максимум.
my %soldiers_by_sn = map { $->{serial_number} => $_ } values %soldiers;
Я нахожу, что одно из преимуществ операционных выражений - то, что это сокращает ошибки, которые прибывают из временных переменных.
Если г-н McCoy хочет отфильтровать всех Hatfield для рассмотрения, можно добавить, что сверяются с минимальным кодированием.
my %soldiers_by_sn
= map { $->{serial_number}, $_ }
grep { $_->{name} !~ m/Hatfield$/ }
values %soldiers
;
Я могу продолжить объединять их в цепочку выражение так, чтобы, если мое взаимодействие с этими данными должно достигнуть глубоко конкретной цели, я не писал много кода, который притворяется, что я собираюсь сделать намного больше.
Генерируйте пароль:
$ perl -E'say map {chr(32 + 95 * rand)} 1..16'
# -> j'k=$^o7\l'yi28G
"Просто сахар" резок. Помните, цикл является просто сахаром - if's и goto могут сделать все, что конструкции цикла делают и т.д.
Карта является достаточно высокой функцией уровня, что она помогает Вам держать намного более сложные операции в голове, таким образом, можно кодировать и отладить большие проблемы.
Для перефразирования "Эффективного Программирования Perl" Hall & Schwartz картой можно злоупотребить, но я думаю, что это лучше всего используется для создания нового списка из существующего списка.
Создайте список квадратов 3,2, и 1:
@numbers = (3,2,1);
@squares = map { $_ ** 2 } @numbers;
Функция карты выполняет выражение на каждом элементе списка и возвращает результаты списка. Позволяет говорят, что у меня был следующий список
@names = ("andrew", "bob", "carol" );
, и я хотел использовать для своей выгоды первую букву каждого из этих имен. Я мог циклично выполниться через них и назвать ucfirst каждого элемента, или я мог просто сделать следующий
@names = map (ucfirst, @names);
карта используется для создания списка путем преобразования элементов другого списка.
grep используется для создания списка путем фильтрации элементов другого списка.
вид используется для создания списка путем сортировки элементов другого списка.
Каждый из этих операторов получает блок кода (или выражение), который используется, чтобы преобразовать, отфильтровать или сравнить элементы списка.
Для карты результат блока становится одним (или больше) элемент (элементы) в новом списке. Элемент тока искажается к $ _.
Для grep решает булев результат блока, будет ли элемент исходного списка скопирован в новый список. Элемент тока искажается к $ _.
Для вида блок получает два элемента (искаженный к $a и $b) и, как ожидают, возвратит один из-1, 0 или 1, указывая, больше ли $a, равен или меньше, чем $b.
Schwartzian Преобразовывают, использует эти операторы для эффективного кэширования значений (свойства), которые будут использоваться в сортировке списка, особенно когда вычисления этих свойств имеют нетривиальную стоимость.
Это работает путем создания промежуточного массива, который имеет как ссылки массива элементов с исходным элементом и вычисленным значением, по которому мы хотим отсортировать. Этот массив передается виду, который сравнивает уже вычисленные значения, создавая другой промежуточный массив (этот отсортирован), который в свою очередь передается другой карте, которая выбрасывает кэшируемые значения, таким образом восстанавливая массив к его начальным элементам списка (но в желаемом порядке теперь).
Пример (создает список файлов в текущем каталоге, отсортированном ко времени их последнего изменения):
@file_list = glob('*');
@file_modify_times = map { [ $_, (stat($_))[8] ] } @file_list;
@files_sorted_by_mtime = sort { $a->[1] <=> $b->[1] } @file_modify_times;
@sorted_files = map { $_->[0] } @files_sorted_by_mtime;
Путем объединения в цепочку операторов вместе, никакое объявление переменных не необходимо для промежуточных массивов;
@sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, (stat($_))[8] ] } glob('*');
Можно также отфильтровать список прежде, чем отсортировать путем вставки grep (если Вы хотите отфильтровать на том же кэшируемом значении):
Пример (список файлов, измененных за прошлые 24 часа, отсортированные время последнего изменения):
@sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } grep { $_->[1] > (time - 24 * 3600 } map { [ $_, (stat($_))[8] ] } glob('*');
Это также удобно для того, чтобы сделать хеши поиска:
my %is_boolean = map { $_ => 1 } qw(true false);
эквивалентно
my %is_boolean = ( true => 1, false => 1 );
Там нет очень сбережений, но предположите, что Вы хотели определить %is_US_state
?
См. также , Schwartzian преобразовывают для усовершенствованного использования карты.
map
функция используется для преобразования списков. Это - в основном синтаксический сахар для замены определенных типов for[each]
циклы. После того как Вы переносите голову вокруг этого, Вы будете видеть использование для него везде:
my @uppercase = map { uc } @lowercase;
my @hex = map { sprintf "0x%x", $_ } @decimal;
my %hash = map { $_ => 1 } @array;
sub join_csv { join(',', map {'"' . $_ . '"' } @_ }
В первую очередь, это - простой способ преобразовать массив: вместо высказывания, например.
my @raw_values = (...);
my @derived_values;
for my $value (@raw_values) {
push (@derived_values, _derived_value($value));
}
можно сказать
my @raw_values = (...);
my @derived_values = map { _derived_value($_) } @raw_values;
Это также полезно для создания быстрой справочной таблицы: вместо, например.
my $sentence = "...";
my @stopwords = (...);
my @foundstopwords;
for my $word (split(/\s+/, $sentence)) {
for my $stopword (@stopwords) {
if ($word eq $stopword) {
push (@foundstopwords, $word);
}
}
}
Вы могли сказать
my $sentence = "...";
my @stopwords = (...);
my %is_stopword = map { $_ => 1 } @stopwords;
my @foundstopwords = grep { $is_stopword{$_} } split(/\s+/, $sentence);
Также полезно, если Вы хотите получить один список от другого, но не должны особенно иметь временной переменной, загромождающей место, например, а не
my %params = ( username => '...', password => '...', action => $action );
my @parampairs;
for my $param (keys %params) {
push (@parampairs, $param . '=' . CGI::escape($params{$param}));
}
my $url = $ENV{SCRIPT_NAME} . '?' . join('&', @parampairs);
Вы говорите намного более простое
my %params = ( username => '...', password => '...', action => $action );
my $url = $ENV{SCRIPT_NAME} . '?'
. join('&', map { $_ . '=' . CGI::escape($params{$_}) } keys %params);
(Редактирование: зафиксированный недостающие "ключи %params" в той последней строке)
Функция карты является идеей от парадигмы функционального программирования. В функциональном программировании функции являются первоклассными объектами, означая, что они могут быть переданы как аргументы другим функциям. Карта является простым, но очень полезным примером этого. Это берет в качестве его аргументов функцию (позволяет, называют его f
), и список l
. f
должна быть функция, берущая один аргумент, и карта просто применяется f
к каждому элементу списка l
. f
может сделать то, в чем Вы нуждаетесь сделанный к каждому элементу: добавьте тот к каждому элементу, придайте каждому элементу квадратную форму, запишите каждый элемент в базу данных или откройте окно веб-браузера для каждого элемента, который, оказывается, допустимый URL.
преимущество использования map
состоит в том, что оно приятно инкапсулирует итерацию по элементам списка. Все, что необходимо сделать, говорят, "делают f
к каждому элементу, и это [до 118], чтобы решить, как лучше всего сделать это. Например map
может быть реализован для разделения его работы среди нескольких потоков, и это было бы полностью очевидно для вызывающей стороны.
Примечание, это map
нисколько не характерно для Perl. Это - стандартная техника, используемая функциональными языками. Это может даже быть реализовано в C, использующем указатели функции, или в C++ с помощью "функциональных объектов".