Сортировка массива Ссылка на хэши - PullRequest
9 голосов
/ 29 июня 2010

После выполнения этих строк в Perl:

my $data = `curl '$url'`;
my $pets = XMLin($data)->(pets);

У меня есть ссылка на массив, который содержит ссылки на хэши:

$VAR1 = [
      {
        'title' => 'cat',
        'count' => '210'
      },
      {
        'title' => 'dog',
        'count' => '210'
      }
]

В Perl как отсортировать хэши сначала по количеству, а затем по заголовку. Затем выведите на STDOUT счетчик с последующим заголовком на каждой новой строке.

1 Ответ

9 голосов
/ 29 июня 2010

При условии, что вы хотите считать в порядке убывания и заголовки по возрастанию:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...