Perl数字排序:如何忽略前导alpha字符

时间:2012-10-11 23:07:05

标签: perl sorting arrays

我有一个1,660行数组:

...
H00504
H00085
H00181
H00500
H00103
H00007
H00890
H08793
H94316
H00217
...

领导人物永远不会改变。它总是“H”然后是五位数。但是,当我在Perl中做我认为是数字排序时,我会得到奇怪的结果。某些段按顺序排序,但随后会启动另一个段。以下是排序后的细分:

...
H01578
H01579
H01580
H01581
H01582
H01583
H01584
H00536
H00537
H00538
H01585
H01586
H01587
H01588
H01589
H01590
...

我正在尝试的是:

my @sorted_array = sort {$a <=> $b} @raw_array;

但显然它不起作用。谁知道为什么?

我应该补充一点,虽然这些值都有“H”前置,但未来我们可能会在其他字母前加上额外的数据。这意味着删除H,排序,然后替换H,不是解决方案

5 个答案:

答案 0 :(得分:9)

如果你正在使用use strict; use warnings;,你可能会遇到很多形式的错误

Argument "H01578" isn't numeric in numeric comparison (<=>)

您的所有元素都不是数字,因此它们都被视为零。这就是Perl认为您当前代码的结果已经排序的原因。


如果您希望按字母排序,则按数字排序(这与按数字排序相同,因为所有字母都相同):

my @sorted_array = sort @raw_array;

的缩写
my @sorted_array = sort { $a cmp $b } @raw_array;

如果您想按编号排序而不考虑前导字母,请改为使用以下内容:

my @sorted_array =
   sort { substr($a, 1) <=> substr($b, 1) }
    @raw_array;

答案 1 :(得分:5)

如果您希望按初始字符排序为主键,后跟数字作为辅助键,则可以使用Schwartzian Transform的变体,在排序之前从所有数据中提取两个字段进行比较。 / p>

该程序演示

use strict;
use warnings;

my @data = <DATA>;
chomp @data;

my @sorted = sort map $_->[0],
sort { $a->[1] cmp $b->[1] or $a->[2] <=> $b->[2] }
map [$_, /(.)(.+)/], @data;

print "$_\n" for @sorted;

__DATA__
A1180
B0802
B1284
C0899
C1455
C0765
A1207
A0909
C0921
C1060
A1067
B1486
A1268
B0772
C0595
B0734
A1004
A0607
A1323
B1181

<强>输出

A0607
A0909
A1004
A1067
A1180
A1207
A1268
A1323
B0734
B0772
B0802
B1181
B1284
B1486
C0595
C0765
C0899
C0921
C1060
C1455

工具已成功完成

您可能更喜欢使用不使用Transform的替代方法。该程序具有相同的输出,但对于大型数据集而言运行速度要慢得多

my @sorted = sort {
  my @a = $a =~ /(.)(.+)/;
  my @b = $b =~ /(.)(.+)/;
  $a[0] cmp $b[0] or $a[1] <=> $b[1];
} @data;

答案 2 :(得分:3)

要忽略任何不是数字的内容,您还可以:

use strict;
use warnings;

my @sorted =    sort {
                        (my $x = $a) =~ s/\D//g;
                        (my $y = $b) =~ s/\D//g;
                        ($x?$x:0) <=> ($y?$y:0)
                } <DATA>;
print "$_" for @sorted;

__DATA__
a123
a/9999/gyu
b2
333
bbb
c888hh
0

结果:

bbb
0
b2
a123
333
c888hh
a/9999/gyu

答案 3 :(得分:1)

你想要这样的东西:

my @sorted_array = sort {substr($a, 1) <=> substr($b,1)} @raw_array;

有关示例,请参阅:http://ideone.com/trnfy

如果您使用标准排序,而不使用{...},则该标准排序也可以正常运行。您当前的代码可能会失败,因为所有比较都返回0,因为您正在对字母数字数据进行数字比较。

答案 4 :(得分:1)

您可以使用List::UtilsBy::sort_by

来避免Schwartzian变换和其他相关噪声
use List::UtilsBy qw( sort_by );

my @sorted_array = sort_by { substr($_, 1) } @raw_array;