При условии, что вы хотите считать в порядке убывания и заголовки по возрастанию:
print map join(" ", @$_{qw/ count title /}) . "\n",
sort { $b->{count} <=> $a->{count}
||
$a->{title} cmp $b->{title} }
@$pets;
Это компактный код, написанный в функциональном стиле.Чтобы понять это, давайте рассмотрим эквивалентный код в более привычном, императивном стиле.
Оператор Perl sort
принимает необязательный параметр SUBNAME, который позволяет вам вычленить сравнение и датьэто имя, которое описывает то, что он делает.Когда я делаю это, мне нравится начинать имя сабвуфера с by_
, чтобы сделать sort by_...
более естественным.
Для начала вы могли бы написать
sub by_count_then_title {
$b->{count} <=> $a->{count}
||
$a->{title} cmp $b->{title}
}
my @sorted = sort by_count_then_title @$pets;
Обратите внимание, что нетзапятая следует за ФИО в этой форме!
Чтобы ответить на вопрос другого комментатора, вы можете использовать or
вместо ||
в by_count_then_title
, если вы найдете его более читабельным.И <=>
, и cmp
имеют более высокий приоритет (что может показаться вам более жестким связыванием), чем ||
и or
, так что это строго вопрос стиля.
Для печати отсортированного массива более знакомым может быть
foreach my $p (@sorted) {
print "$p->{count} $p->{title}\n";
}
Perl использует $_
, если вы не укажете переменную, которая получает каждое значение, поэтому следующее значение имеет то же значение:
for (@sorted) {
print "$_->{count} $_->{title}\n";
}
Ключевые слова for
и foreach
являются синонимами, но я считаю, что приведенные выше варианты использования т.е. , foreach
, если я собираюсь назвать переменную или for
иначе читайте наиболее естественно.
Использование map
, близкого кузена foreach
, не сильно отличается:
map print("$_->{count} $_->{title}\n"), @sorted;
Вы также можете повысить print
черезmap
:
print map "$_->{count} $_->{title}\n",
@sorted;
Наконец, чтобы избежать повторения $_->{...}
, срез хеша @$_{"count", "title"}
дает нам значения, связанные с count и title в текущей записи цикла,Имея значения, нам нужно соединить их с одним пробелом и добавить новую строку к результату, поэтому
print map join(" ", @$_{qw/ count title /}) . "\n",
@sorted;
Помните, что qw//
является сокращениемдля написания списка строк.Как показывает этот пример, прочитайте выражение map
спереди назад (или снизу вверх так, как я его отступил): сначала отсортируйте записи, затем отформатируйте их, а затем напечатайте.
Youможет устранить временное @sorted
, но вызвать именованное сравнение:
print map join(" ", @$_{qw/ count title /}) . "\n",
sort by_count_then_title
@$pets;
Если применение join
слишком многословно на ваш вкус, то
print map "@$_{qw/ count title /}\n",
sort by_count_then_title
@$pets;