2

我有一个像这样的 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,不是解决方案

4

5 回答 5

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;
于 2012-10-12T02:19:32.397 回答
5

如果您想按初始字符作为主键,然后将数字作为辅助键进行排序,那么您可以使用Schwartzian 变换的变体,它在排序之前从所有数据中提取两个字段进行比较。

这个程序演示

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

工具成功完成

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

my @sorted = sort {
  my @a = $a =~ /(.)(.+)/;
  my @b = $b =~ /(.)(.+)/;
  $a[0] cmp $b[0] or $a[1] <=> $b[1];
} @data;
于 2012-10-12T07:46:57.713 回答
4

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

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
于 2012-10-12T13:19:20.797 回答
1

你想要这样的东西:

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

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

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

于 2012-10-12T02:03:06.667 回答
1

您可以使用以下方法避免 Schwartzian 变换和其他相关噪声List::UtilsBy::sort_by

use List::UtilsBy qw( sort_by );

my @sorted_array = sort_by { substr($_, 1) } @raw_array;
于 2012-10-12T13:43:32.760 回答