我在perl中有一个数组,有一些间隔,如:
@array = qw(1-5 7-9 10-15 20-58 123-192 234-256)
我正在尝试使用sort来订购它,但这是我获得的:
1-5,10-15,123-192,20-58,234-256,7-9
按第一个数字的第一个字符排序...如何获取整个第一个数字以获得下一个数组?
1-5,7-9,10-15,20-58,123-192,234-256
非常感谢!
P.S。
我没有这个代码,我正在尝试命令
my @sorted = sort @array;
答案 0 :(得分:5)
您需要为每个元素提取第一个数字,并使用<=>
运算符
my @array = qw(1-5 7-9 10-15 20-58 123-192 234-256);
my @sorted = sort {
my ($aa,$bb) = map /^([0-9]+)/, $a,$b;
$aa <=> $bb;
} @array;
答案 1 :(得分:5)
您想要做的是按数字排序。为此,您需要通过提供自己的方法来覆盖默认排序方法。这段代码:
my @sorted = sort @array;
真的意味着:
my @sorted = sort { $a cmp $b } @array;
其中cmp
是词典比较运算符(按字母顺序排序,或多或少)。您想使用<=>
,通常称为&#34;太空船运营商&#34;。
my @sorted = sort { $a <=> $b } @array;
但是这个运算符只能用于数字,而7-9
这样的字符串实际上并不是一个数字(尽管在这种情况下它会起作用,尽管发出警告Argument "7-9" isn't numeric in sort
)。
要克服此警告和可能的错误,我们需要从要排序的字符串中提取数字。我们使用正则表达式匹配执行此操作:/\d+/g
。这将匹配并返回字符串中的所有连续数字。
my @sorted = sort {
my ($a1, $a2) = $a =~ /\d+/g;
my ($b1, $b2) = $b =~ /\d+/g;
$a1 <=> $b1 || $a2 <=> $b2;
} @array;
我们捕获并使用低和高范围,最后我们执行两项检查。这意味着,在$a1
和$b1
相等的情况下,<=>
返回0
,||
运算符执行备用比较,{{1} }。
在某些情况下,此操作很昂贵,需要时间,并且对于大型数据集,它将导致排序变得非常慢。在这种情况下,我们可以使用所谓的Schwartzian transform来缓存数据。在这个方法中,我们只是存储正则表达式匹配的值,并在排序时使用存储的值。为此,我们使用匿名数组ref $a2 <=> $b2
。最后,我们恢复原始值并丢弃缓存:
[ ... ]
如果您想要多个排序级别,只需添加my @sorted = map { $_->[0] } # restore original
sort { $a->[1] <=> $b->[1] } # sort compares stored nums
map { [ $_, /\d+/g ] } # store original, and nums
@array;
等等。