Почему моя Perl-карта ничего не возвращает?
Вопрос
Когда я выполняю следующее утверждение:
@filtered = map {s/ //g} @outdata;
он возвращает пустой список вместо отфильтрованного списка, который я ожидал.То, что я пытаюсь сделать, это удалить все вхождения
из массива string (который представляет собой XML-файл).
Очевидно, я чего-то не понимаю.Кто-нибудь может подсказать мне, каким может быть правильный способ сделать это, и почему это не работает у меня как есть?
Решение
Попробуй это:
@filtered = map {s/ //g; $_} @outdata;
Проблема в том, что оператор s в perl изменяет $_, но на самом деле возвращает количество внесенных им изменений.Таким образом, дополнительный $_ в конце приводит к тому, что perl возвращает измененную строку для каждого элемента @outdata.
Другие советы
Обратите внимание, что map также изменит ваш исходный массив.Таким образом, вы могли бы либо сделать:
map {s/ //g} @outdata;
и вообще пропустите переменную @filtered, или, если вам нужно сохранить оригиналы,
@filtered = @outdata;
map {s/ //g} @filtered;
Хотя, в этом случае, было бы более удобно использовать foreach:
s/ //g foreach @filtered;
Проблема ответа Грега заключается в том, что он изменит исходный массив, поскольку $_ передаются с псевдонимами.Вам нужно:
@filtered = map { (my $new = $_) =~ s/ //g; $new} @outdata;
Чтобы развить мысль Титония, это тоже поможет:
@filtered = map {local $_=$_; s/ //g; $_} @outdata;
"Локальный" гарантирует, что вы работаете с копией, а не с оригиналом.
В perl 5.14 вы могли бы использовать /r модификатор регулярного выражения для произвести неразрушающую замену.
@filtered = map {s/ //gr} @outdata;
use Algorithm::Loops "Filter";
@filtered = Filter { s/ //g } @outdata;
В качестве контрапункта к ответу Грега вы могли бы злоупотреблять grep:
@filtered = grep {s/ //g; 1} @outdata;
Не делай этого.