我有以下字符串数组:
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
我想按第一个数字排序这些字符串,然后用第二个数字排序第二个数字,这样我就有了这样的列表:
Expt1_Expt2
Expt5_Expt1
Expt5_Expt12
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt11_Expt8
Expt12_Expt2
我只发现解决方案只按第一个数字或第二个数字排序。我尝试了一些使用正则表达式和排序函数的东西,但我没有找到解决方案。
答案 0 :(得分:9)
按功能排序非常简单。该函数必须返回-1,0或1,具体取决于$a
和$b
之前或之后。 (如评论中所述 - 它可以是任何正值或负值 - 关键点是元素是在彼此之前还是之后)。
$a
和$b
是特殊的'专门用于perl和排序的变量。因此,他们不需要声明,并且在您的代码中用于其他内容的真的坏主意。但那么,谁还使用单字母变量?
所以你的价值观:
#!/usr/bin/env perl
use strict;
use warnings;
sub custom_sort {
my ( $a1, $a2 ) = ( $a =~ m/(\d+)/g ); #extract the numeric elements
my ( $b1, $b2 ) = ( $b =~ m/(\d+)/g );
return ( $a1 <=> $b1 #return the result of this comparison
|| $a2 <=> $b2 ); #unless it's zero, then we return the result of this.
}
my @list = <DATA>;
print sort custom_sort @list;
__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
你可以使这更简洁,但实质是:
||
运算符 - 这样如果$a1 <=> $b1
为零,它将计算表达式的第二部分。 <=>
小于,等于,大于&#39;基于数字比较返回-1,0或1的运算符。对于字符串,您可以使用cmp
执行相同的操作。 (如果您希望调试这种类型的工作方式,那么您可以打印这些,以便进行每次比较,如果您正在做一些复杂的事情,这非常方便)
答案 1 :(得分:2)
这与其他人发布的解决方案基本相同,但使用map
use strict;
use warnings;
my @data = <DATA>;
print sort {
my @ab = map [ /\d+/g ], $a, $b;
$ab[0][0] <=> $ab[1][0] or $ab[0][1] <=> $ab[1][1];
} @data;
__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt1_Expt2
Expt5_Expt1
Expt5_Expt12
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt11_Expt8
Expt12_Expt2
答案 2 :(得分:1)
use Sort::Key::Multi qw(i2_keysort); #i2 means two integer keys
my @sorted = i2_keysort { /(\d+)\D+(\d+)/ } @data;