Архив документации OpenNet.ru / Раздел "Perl" / Индекс

Работа со списками

Задача, есть ряд вида:

.3
.3.1
.3.1.1
.2
.2.1
.2.1.1
.2.1.1.1
.1

Найти максимальное число с максимальным вложением единичек. Решение, если убрать точки, будет максимальным числом. Его и надо выделить:


#!/usr/bin/perl -w
$_=qq~.3
.3.1
.3.1.1
.2
.2.1
.2.1.1
.2.1.1.1
.1
~;

print ".", join "." => split m!! =>
     @{[reverse sort {$a <=> $b} grep{s!\.!!g} split m%\n%]}[0];
print "\n";

Как это работает: конструкця @{[ тут действия со списками ]} возвращает массив элементов, из которого можно выделить нужный по номеру элемента массива @{[blah-blah]}[0]. В переменной $_ содержится искомая "строка" из цифр, поэтому её можно разбивать по переводу каретки: split m%\n%. После split m%\n% для grep{s!\.!!g} возвращается список, который из каждого элемента списка вырезает символ точки(экранированный символ, т.к. символ точки в regex означает любой символ). Дальше возвращается список чисел без точки, которые сортируются при помощи sort {$a <=> $b}. Скобки {$a <=> $b} нужны для того, чтобы была произведена числовая, а не символьная сортировка. Т.е. в случае print join "\n" => sort {$a <=> $b} grep{s!\.!!g} @blah-blah функция sort вернет такой список, где максимальным будет число, содержащее в начале себя тройку как максимальное число, т.е. критическим будет "старший бит":


1
2
21
211
2111
3
31
311

далее при помощи reverse оборачивается возвращаемый sort список и берется нулевой элемент массива, состоящий из числа(в данном случае) 2111(что как число 2111 в целом больше, чем 311). Этот нулевой элемент затем режется по символу ноль(или по пустому символу, ведь между цифрой 2 и 1 не стоит ничего, вот по этому то ничего и режется): split m!! => @{[blah-blah]}[0]. Обычно в конструкции split ставятся два косых слеша split //, $string; эти два косых слеша есть не что иное как поиск по подстановке m//. А при указании буквы m в регулярном выражении слеши можно заменять любыми символами, например split mЫЫ. Далее при обычном синтаксисе ставится запятая, эту запятую можно заменить на стрелочку => без потери функциональности. Итого имеем split m!! => @{[blah-blah]}[0], т.е. массив, который нужно вывести в прежнем виде, т.е. .2.1.1.1, чего и делаем: print ".", join "." => split m!! => @{[blah-blah]}[0]

Другое более короткое решение той-же задачи от Artem Chuprina(from fido7.ru.perl):


perl -lne 'if (/(\d+)/ && ($1 > $num || ($1 == $num && length($_) > 
length($res)))) { $num = $1; $res = $_ }; END { print $res }' test.dat


Архив документации на OpenNet.ru