После выполнения этих строк в Perl:
my $data = `curl '$url'`;
my $pets = XMLin($data)->(pets);
У меня есть ссылка на массив, которая содержит ссылки на хеши:
$VAR1 = [
{
'title' => 'cat',
'count' => '210'
},
{
'title' => 'dog',
'count' => '210'
}
]
В Perl, как я сортирую хеши сначала по количеству и во вторую очередь по заголовку. Затем распечатайте к STDOUT количество, сопровождаемое заголовком на каждой новой строке.
Предположим, вам нужны подсчеты в порядке убывания, а заголовки - по возрастанию:
print map join(" ", @$_{qw/ count title /}) . "\n",
sort { $b->{count} <=> $a->{count}
||
$a->{title} cmp $b->{title} }
@$pets;
Это компактный код, написанный в функциональном стиле. Чтобы понять это, давайте посмотрим на эквивалентный код в более знакомом императивном стиле.
Оператор Perl sort
принимает необязательный параметр SUBNAME, который позволяет выделить ваше сравнение и дать ему имя, описывающее его действия. Когда я делаю это, мне нравится начинать имя подпрограммы с by_
, чтобы сделать сортировку по _...
более естественной.
Для начала, вы могли бы написать
sub by_count_then_title {
$b->{count} <=> $a->{count}
||
$a->{title} cmp $b->{title}
}
my @sorted = sort by_count_then_title @$pets;
Обратите внимание, что в этой форме после ЗАПИСИ не ставится запятая!
Чтобы ответить на вопрос другого комментатора, вы можете использовать или
вместо ||
в by_count_then_title
, если вы сочтете его более читабельным. И <=>
, и cmp
имеют более высокий приоритет (который можно рассматривать как более тесную привязку), чем ||
и или
, так что это строго вопрос стиля.
Для печати отсортированного массива более привычным вариантом может быть
foreach my $p (@sorted) {
print "$p->{count} $p->{title}\n";
}
Perl использует $ _
, если вы не укажете переменную, которая получает каждое значение, поэтому следующее имеет то же значение:
for (@sorted) {
print "$_->{count} $_->{title}\n";
}
Ключевые слова для
и foreach
являются синонимами, но я считаю, что приведенные выше варианты использования, т.е. , foreach
, если я собираюсь называть переменную, или для
в противном случае, читать наиболее естественно.
Использование 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
задом наперед (или снизу вверх, как я сделал отступ): сначала отсортируйте записи, затем отформатируйте их, затем распечатайте.
Вы можете удалить временный @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;