如何在 perl 中对包含两个数字的字符串数组进行排序?
How to sort an array of strings containing two numbers in perl?
我有以下字符串数组:
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
我只找到了仅按第一个数字或第二个数字排序的解决方案。我用正则表达式和排序函数尝试了一些东西,但我没有找到解决方案。
按功能排序非常简单。该函数必须 return -1、0 或 1,具体取决于 $a
和 $b
是在之前还是之后。 (如评论中所述 - 它可以是任何正值或负值 - 关键是元素是在彼此之前还是之后)。
$a
和 $b
是 'special' 变量,专门用于 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
为零,它会计算表达式的第二部分。
<=>
是一个 'less than, equal to, greater than' 运算符,它 returns -1、0 或 1 基于数值比较。对于字符串,您可以使用 cmp
来做同样的事情。
(如果你想为每次比较调试这种排序方式 'working',你可以打印这些,如果你正在做一些复杂的事情,这真的很方便)
这与其他人发布的解决方案大致相同,但通过使用 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
use Sort::Key::Multi qw(i2_keysort); #i2 means two integer keys
my @sorted = i2_keysort { /(\d+)\D+(\d+)/ } @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
我只找到了仅按第一个数字或第二个数字排序的解决方案。我用正则表达式和排序函数尝试了一些东西,但我没有找到解决方案。
按功能排序非常简单。该函数必须 return -1、0 或 1,具体取决于 $a
和 $b
是在之前还是之后。 (如评论中所述 - 它可以是任何正值或负值 - 关键是元素是在彼此之前还是之后)。
$a
和 $b
是 'special' 变量,专门用于 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
为零,它会计算表达式的第二部分。 <=>
是一个 'less than, equal to, greater than' 运算符,它 returns -1、0 或 1 基于数值比较。对于字符串,您可以使用cmp
来做同样的事情。
(如果你想为每次比较调试这种排序方式 'working',你可以打印这些,如果你正在做一些复杂的事情,这真的很方便)
这与其他人发布的解决方案大致相同,但通过使用 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
use Sort::Key::Multi qw(i2_keysort); #i2 means two integer keys
my @sorted = i2_keysort { /(\d+)\D+(\d+)/ } @data;