Пустые списки
Три списка отличаются тем, что регулярное выражение
/=(\d+)/
может вернуть пустой список (если он не совпадает) --- испортить ваши структуры. Я вставил в ваш код следующие строки и получил указанные ответы:
say "nums: @nums"; # nums: 332 43 3322
say "caps: @caps"; # caps: =332 =43 =AVXC =AED =JJJ =3322 =AA44 =SSSS
Видите ли, любой элемент, который не соответствует регулярному выражению, отсутствует в @nums и портит ваш список.
Это можно исправить, изменив определение @nums на:
push @nums, /=(\d+)/? $1:undef;
( Редактировать: добавлено уточнение) Та же проблема возникает в вашем последнем примере:
For $_="=123", [$_, /=(\d+)/, uc($_)] = ["123", 123, 123].
For $_="abcd", [$_, /=(\d+)/, uc($_)] = ["abcd", "ABCD"].
Совпадение исчезает, и строка в верхнем регистре перемещается на свое место. Это не то, что вы хотели. Одним из исправлений является замена регулярного выражения, как указано выше, выражением, которое всегда выдает ровно один скаляр:
[$_, /=(\d+)/? $1:undef, uc($_)]
Другим решением было бы поменять местами два последних элемента в списке:
@new = map { $_->[0] }
sort { $b->[2] <=> $a->[2]
||
$a->[1] cmp $b->[1]
} map { [$_, uc($_), /=(\d+)/] } @old;
say "new_3: @new\n";
Теперь регулярное выражение в конце. Если совпадений нет, список будет коротким (всего два элемента). Тем не менее, $ a -> [2] дает желаемый результат: undef.
(Вам может понравиться или не понравиться этот подход, позволяющий кусать ошибку, но иметь правильный результат как побочный эффект чтения perl за пределами более коротких списков).
С этими исправлениями все три списка дают одинаковый результат.
Предупреждения
Пожалуйста, запустите вашу программу с включенным предупреждением "-w". Вы обнаружите, что сравниваете довольно много неопределенных значений и нечисловых значений. Вы должны исправить свою программу, чтобы обойтись без этого, например:
@new = map { $_->[0] }
sort {
defined($b->[2]) && defined($a->[2]) && ($b->[2] <=> $a->[2])
||
$a->[1] cmp $b->[1]
} map { [$_, uc($_), /=(\d+)/] } @old;
say "new_4: @new\n";