Сортировка ссылки на массив к хешам

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

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

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

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

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

9
задан syker 29 June 2010 в 01:49
поделиться

1 ответ

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

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;
9
ответ дан 4 December 2019 в 21:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: