#! /usr/bin/perl -w # This code is public domain; I never assert any rights. # This code is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. use strict; use constant COND_DTYPE_STR => 0; use constant COND_DTYPE_NUM => 1; use constant COND_ORDER_ASC => 0; use constant COND_ORDER_DESC => 1; MAIN: { my @data = ("foo,bar,2,3,4", "foo,bar,3,4,5", "fog,bar,2,2,2", "fgh,bar,3,4,2", "foo,bar,4,5,6"); my @ordered = ayumoesort(\@data, {dtype => COND_DTYPE_NUM, order => COND_ORDER_ASC, keyno => 2}, {dtype => COND_DTYPE_STR, order => COND_ORDER_DESC, keyno => 0}); print "$_\n" foreach @ordered } sub ayumoesort { my $dref = shift; my @cond = @_; my @sgn = map { -($_->{order}*2 - 1) } @cond; # ASC: +1, DESC: -1 # Schwartz Transform; cf. Effective Perl or ask Google # equivalent to: # @tmp = map { ... } @$dref; # @tmp = sort { ... } @tmp; # @$dref = map { ... } @tmp; @$dref = (map { $_->[-1] } sort { foreach my $i (0..$#cond) { my $r; if($cond[$i]{dtype} == COND_DTYPE_STR) { $r = $sgn[$i]*($a->[$i] cmp $b->[$i]) and return $r; } elsif($cond[$i]{dtype} == COND_DTYPE_NUM) { $r = $sgn[$i]*($a->[$i] <=> $b->[$i]) and return $r; } else { die; } } } map { my $x = $_; [(map { (split /,/, $x)[$cond[$_]{keyno}] } (0..$#cond)), $_] } @$dref); }