2010-06-29 20 views
9

Po wykonaniu tych linii w Perlu:Sortowanie Reference tablicę wartości mieszania

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

mam odniesienie tablicę, która zawiera odniesienia do skrótów:

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

w Perl, w jaki sposób mogę rozwiązać mieszań najpierw według liczby i wtórnie według tytułu. Następnie wydrukuj do STDOUT liczbę, a następnie tytuł na każdym nowym wierszu.

Odpowiedz

9

Zakładając chcesz liczby w kolejności malejącej i tytuły wstępnego:

print map join(" ", @$_{qw/ count title /}) . "\n", 
     sort { $b->{count} <=> $a->{count} 
         || 
      $a->{title} cmp $b->{title} } 
     @$pets; 

To jest zwarty kod napisany w stylu funkcjonalnym. Aby to zrozumieć, spójrzmy na równoważny kod w bardziej znanym, imperatywnym stylu.

Operator Perla za sort przyjmuje opcjonalny parametr SUBNAME, który pozwala na zoptymalizowanie porównania i nadanie mu nazwy opisującej to, co robi. Kiedy to robię, chciałbym zacząć sub nazwę od by_, aby uczynić sort by_... bardziej naturalną.

Aby rozpocząć, może masz napisane

sub by_count_then_title { 
    $b->{count} <=> $a->{count} 
       || 
    $a->{title} cmp $b->{title} 
} 

my @sorted = sort by_count_then_title @$pets; 

Zauważ, że nie przecinek następuje SUBNAME w tej postaci!

Aby odpowiedzieć na pytanie innego komentatora, możesz użyć or zamiast || w by_count_then_title, jeśli uznasz, że jest bardziej czytelny. Zarówno <=>, jak i cmphave higher precedence (które można uważać za wiążące ściślej) niż || i or, więc jest to ściśle kwestią stylu.

Aby wydrukować posortowaną tablicę, bardziej zaznajomieni wybór może być

foreach my $p (@sorted) { 
    print "$p->{count} $p->{title}\n"; 
} 

Perl używa $_ jeśli nie określić zmienną, która pobiera każdą wartość, więc następujący ma takie samo znaczenie:

for (@sorted) { 
    print "$_->{count} $_->{title}\n"; 
} 

for i foreach słowa kluczowe są synonimami, ale uważam, że powyższe zastosowania, tj, foreach jeśli mam zamiar wymienić var W przeciwnym razie, odczytaj w sposób naturalny.

Korzystanie map, bliski kuzyn foreach, zamiast nie różni się zbytnio:

map print("$_->{count} $_->{title}\n"), @sorted; 

Można również promować print przez map:

print map "$_->{count} $_->{title}\n", 
     @sorted; 

koniec, aby uniknąć powtórzenia $_->{...} , hash slice@$_{"count", "title"} podaje wartości związane z liczbą i tytułem w bieżącym rekordzie pętli.Uwzględniając wartości, musimy join je z jednego miejsca i dołączyć do nowej linii do wyniku, więc

print map join(" ", @$_{qw/ count title /}) . "\n", 
     @sorted; 

Pamiętaj, że qw// jest skrótem pisząc listy ciągów. Jak pokazuje ten przykład, odczytaj wyrażenie z tylu do przodu (lub od dołu do góry w sposób, w jaki go wcięłam): najpierw sortuj rekordy, a następnie formatuj je, a następnie drukuj.

Można wyeliminować tymczasowe @sorted ale nazwać imieniem porównania:

print map join(" ", @$_{qw/ count title /}) . "\n", 
     sort by_count_then_title 
     @$pets; 

Jeżeli stosowanie join jest po prostu zbyt rozwlekły do ​​smaku, a następnie

print map "@$_{qw/ count title /}\n", 
     sort by_count_then_title 
     @$pets; 
+0

Co oznacza „map” oznaczać/zrobić w powyższym kodzie? I dlaczego nie musimy określać dwóch atrybutów w dwóch różnych zestawach nawiasów klamrowych? – syker

+0

@syker: 'map' pobiera każdy skrót w posortowanej tablicy i wypisuje wartości' count' i 'title' na linii rozdzielonej spacjami. @ gbacon: Warto wyjaśnić, czy jest jakaś różnica między używaniem '||' i 'lub' w twoim sortowaniu, ponieważ zawsze widzę '||' w przykładach sortowania za cokolwiek. Czy istnieje możliwość, że bardziej czytelne "lub" zachowuje się inaczej w każdych okolicznościach? – Zaid

+0

@syker @Zaid Zobacz zaktualizowaną odpowiedź. –

Powiązane problemy