Thread Sortierung nach Array (18 answers)
Opened by bianca at 2012-12-25 18:11

murphy
 2012-12-30 17:03
#164526 #164526
User since
2004-07-19
1776 articles
HausmeisterIn
[Homepage]
user image
Der Code
Code (perl): (dl )
{index => 2, collate => NUMERIC, order => ASC}

erzeugt eine anonyme Hashreferenz, die unter anderem den Schlüssel 'collate' auf den Wert abbildet, welchen der Subroutinenaufruf NUMERIC() zurückgibt.

Die Subroutine NUMERIC wurde zuvor mit Hilfe des Moduls CPAN:constant erzeugt und gibt ihrerseits stets eine Subroutinenreferenz auf einen bestimmten Vergleichsoperator zurück.

Der Code, der NUMERIC aufruft, muss natürlich diese Konstante bzw. spezielle Subroutine importiert haben. Möchte man das unbedingt vermeiden, so kann man stattdessen zum Beispiel den Sortiercode so abwandeln, dass er Strings in einem Hash nachschlägt.

Hier eine Variante meines ursprünglichen Code, die diese Strategie verfolgt:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use 5.012;
use warnings;

my %collations = (
    ALPHA => sub { my ($a, $b) = @_; $a cmp $b },
    NUMERIC => sub { my ($a, $b) = @_; $a <=> $b },
);

my %orders = (
    ASC => +1,
    DSC => -1
);

# Multicolumn sort function.
# Params:
#   $columns = Arrayref of sort column definitions in priority order.
#              Each column definition is a hashref with the keys
#                index   => Column index in the data rows
#                collate => Collation order
#                order   => 'ASC' for ascending or 'DSC' for descending order
#   $data    = Arrayref of data rows
# Returns:
#   Arrayref of sorted data rows
sub multisort {
    my ($columns, $data) = @_;
    [sort {
        for my $column (@$columns) {
            my $order = $orders{$column->{order}} or die 'illegal sort order ' . $column->{order};
            my $collate = $collations{$column->{collate}} or die 'illegal collation sequence ' . $column->{collate};
            my $index = $column->{index};
            my $d = $order * $collate->($a->[$index], $b->[$index]);
            return $d unless $d == 0;
        }
    } @$data];
}

# Runnable example:
my @data = (
    ['aaron', 'zander', 20],
    ['hannes', 'zander', 20],
    ['aaron', 'suppe', 10],
);

my @columns = (
    {index => 2, collate => 'NUMERIC', order => 'ASC'},
    {index => 1, collate => 'ALPHA', order => 'ASC'},
    {index => 0, collate => 'ALPHA', order => 'ASC'},
);

use Data::Dumper;
print Dumper multisort(\@columns, \@data);
When C++ is your hammer, every problem looks like your thumb.

View full thread Sortierung nach Array