Почему эта карта возвращает одно число?
-
22-09-2019 - |
Вопрос
Я пытаюсь сократить количество строк кода, которые я использую, но в итоге сталкиваюсь с довольно простой проблемой (хотя это ставит меня в тупик, поскольку я только начинаю разбираться со ссылками)
Я пытаюсь объединить несколько значений в определенном порядке..Мой код выглядит примерно так..
my $separator = ":";
my @vals = qw(name last-name first-name phone);
my $return_name;
$return_name = map {
$return_name = $return_name . $query->param($_) . $separator
} @vals;
То, что я получаю, - это "4", вместо объединения всех в одну строку.
То , чего я пытаюсь достичь , - это более короткая версия ...
$return_name = $query->param('name') .
$separator . $query->param('last-name') .
$separator . $query->param('first_name') .
$separator . $query->param('phone');
(На самом деле я пытаюсь собрать воедино около 25 $query->params
.Я привел только четыре для краткости)
Решение
Часть вашей проблемы - это путаница в том, как map
работает.
map
принимает список аргументов, выполняет операцию над элементами списка и создает новый список из результатов.В скалярном контексте он возвращает количество элементов в новом списке.
В большинстве случаев вы не хотите выполнять задание в map
операция.
# no assignment needed to set @foo
my @foo = map $_+2, 1,2,3;
# @foo = (3,4,5);
Единственное место, где назначение имеет смысл, - это если вам нужно использовать операцию, которая обычно изменяет значение $_
, но вам нужно сохранить аргументы для сопоставления без изменений.
Это объяснение не очень понятно.Ознакомьтесь с этими примерами, они должны помочь прояснить то, что я говорю.На первом показано, что карта может изменять значения, которые она обрабатывает:
my @foo = qw( fee fie foe fum );
my @bar = map { s/e/-/g } @foo;
# @foo = ( 'f--', 'fi-', 'fo-', 'fum' );
# @bar = ( 2, 1, 1, '' );
Чтобы избежать изменения @foo, вы можете сделать:
my @foo = qw( fee fie foe fum );
my @bar = map { my $val = $_; $val =~ s/e/-/g } @foo;
# @foo = ( 'fee', 'fie', 'foe', 'fum' );
# @bar = ( 'f--', 'fi-', 'fo-', 'fum' );
Или вы можете сделать:
список использований::Дополнительные утилиты qw( применить);
my @foo = qw( fee fie foe fum );
my @bar = apply { s/e/-/g } @foo;
# @foo = ( 'fee', 'fie', 'foe', 'fum' );
# @bar = ( 'f--', 'fi-', 'fo-', 'fum' );
На самом базовом уровне map
работает как специализированная форма for
петля.Два фрагмента кода дают точно такой же результат:
my @foo = map {$_ * 2} 1..5;
my @bar;
for (1..5) {
my $val = $_ * 2;
push @bar, $val;
}
Я надеюсь, что это помогло вам научиться думать о map
.Как только вы научитесь использовать его (и связанные с ним конструкции, такие как grep
и apply
) вы сможете кратко выражать идеи, которые могут быть невероятно подробными при создании с использованием обычного циклического кода.
Другие советы
$return_name = map { $return_name = $return_name . $query->param($_) . $separator } @vals;
Это скалярное присвоение, которое придает операции map скалярный контекст.Карта в скалярном контексте возвращает количество элементов, которые были бы созданы.
В то время как эта конкретная строка кода взывает к использованию присоединиться(), если вы имеете опыт функционального программирования, вам может быть удобнее использовать reduce:
use List::Util 'reduce';
$return_name = reduce { $a . $query->param($b) . $separator } "", @vals;
map
возвращает список, а не строку.Попробуй это:
$return_name = join $separator, map { $query->param($_) } @vals;
Или, если вы действительно хотите сократить количество строк, попробуйте следующее:
my $return_name = join ':',
map { $query->param($_) }
qw(name last-name first-name phone);
(Однострочная версия была вдохновлена ответом dsm.)
Попробуй это:
join $separator,
map { $query->param($_) }
("name", "last-name", "first-name", "phone");
Чтобы ответить на причину, по которой вы получаете '4', это потому, что вы присваиваете результирующую мощность массивов скаляру.
В дополнение ко всем хорошим ответам, которые вы получили, обратите внимание, что
$return_name = $return_name . $query->param($_) . $separator;
может быть записан как
$return_name .= $query->param($_) . $separator;