1

Given an array of Letter_Number combinations, how can I sort by letter first, then number:

( B_5   A_11   C_0   A_10    A_1 )

to get:

( A_1   A_10   A_11   B_5    C_0 )

?

4

5 回答 5

5

默认情况下,sort 按词法比较。因此,如果您想将数字视为 010 > 1 和 2 < 11 的实际数字,那么这更像是您需要的:

my @list = qw(B_5 A_11 C_0 A_10 A_1);
my @sorted = sort char_then_num @list;

sub char_then_num {
    my ($a_char, $a_num) = split '_', $a;
    my ($b_char, $b_num) = split '_', $b;
    return $a_char cmp $b_char
             ||
        $a_num <=> $b_num;
}
于 2013-07-11T19:27:06.263 回答
4
use Sort::Key::Natural qw( natsort );
my @sorted = natsort @data;

或者,如果您想避免使用模块,

my @sorted =
   map $_->[0],
    sort {  $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] }
     map [ $_, split /_/ ],
      @data;
于 2013-07-11T19:35:17.887 回答
1

简单高效:

my @list = qw(B_5 A_11 C_0 A_10 A_2);

my @sorted = map $_->[0], sort {$a->[1] cmp $b->[1] or $a->[2] <=> $b->[2]} map [$_, split'_'], @list;

编辑

即使对于非常小的值,使用 Schwartzian 变换也会产生巨大的差异:

#!/usr/bin/perl

use Benchmark qw( cmpthese );

our $chars = join("","A".."Z");

sub genlist
{
    my $count = shift;
    return map join("_", substr($chars, rand(26),1), int(rand(100))),
        1 .. $count;
}

sub nostcmp {
    my ($a_char, $a_num) = split '_', $a;
    my ($b_char, $b_num) = split '_', $b;
    return $a_char cmp $b_char
             ||
        $a_num <=> $b_num;
}

sub nost {
   return sort nostcmp @_;
}

sub st {
    return
       map $_->[0],
        sort { $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] }
         map [ $_, split '_' ],
          @_;
}


my %tests = (
   nost => 'my @sorted = nost(@list);',
   st   => 'my @sorted = st(@list);',
);


$_ = 'use strict; use warnings; our @list; ' . $_
   for values %tests;

sub measure
{
    my $count = shift;
    print "Count $count:\n";
    local our @list = genlist($count);
    cmpthese(-3, \%tests);
    print "\n";
}

measure $_ for 5,10,20,50,100;

和结果:

Count 5:
         Rate nost   st
nost  82195/s   -- -21%
st   103392/s  26%   --

Count 10:
        Rate nost   st
nost 35430/s   -- -34%
st   53589/s  51%   --

Count 20:
        Rate nost   st
nost 13228/s   -- -48%
st   25277/s  91%   --

Count 50:
       Rate nost   st
nost 4157/s   -- -53%
st   8935/s 115%   --

Count 100:
       Rate nost   st
nost 1637/s   -- -58%
st   3889/s 138%   --
于 2013-07-11T19:37:31.640 回答
1

试试 CPAN 模块 Sort::Naturally。

于 2013-07-11T19:28:06.610 回答
-2

您正在寻找的顺序已经是排序的默认行为......所以只需排序:

my @list = qw(B_5 A_11 C_0 A_10 A_1);
my @sorted = sort @list;
于 2013-07-11T19:20:21.153 回答