如何使用两个子字符串相等条件对字符串进行排序?
How to sort strings using two substring equality conditions?
我有一个字符串列表,格式如下:
('group1-1', 'group1-2','group1-9', 'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' )
我需要按如下方式排序:
先分组,再分组。
('group1-1', 'group1-2','group1-9','group1-10', 'group2-1','group2-2', 'group2-9', 'group2-10' )
我编写了以下代码,但没有按预期运行:
一个根据组排序的比较器,如果组匹配,它根据数字排序。
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' );
@list = sort compare @list;
for (@list){
print($_."\n");
}
sub compare{
my $first_group, $first_num = get_details($a);
my $second_group, $second_num = get_details($b);
if($first_group < $second_group){
return -1;
} elsif($first_group == $second_group){
if ( $first_num < $second_num) {
return -1;
} elsif ( $first_num == $second_num ) {
return 0;
} else {
return 1;
}
} else{
return 1;
}
}
sub get_details($){
my $str= shift;
my $group = (split /-/, $str)[0];
$group =~ s/\D//g;
my $num = (split /-/, $str)[1];
$num =~ s/\D//g;
return $group, $num;
}
我会确保列表中的字符串遵循模式 (\S+\d+-\d+
),然后使用 cmp
作为字符串比较部分,使用 <=>
作为数字:
sub compare {
if( $a =~ /(\S+)(\d+)-(\d+)/ ) {
my($A1,$A2,$A3) = (,,);
if( $b =~ /(\S+)(\d+)-(\d+)/ ) {
my($B1,$B2,$B3) = (,,);
return ($A1 cmp $B1) || ($A2 <=> $B2) || $A3 <=> $B3;
}
}
$a cmp $b; # fallback if a string doesn't follow the pattern
};
您可以使用 Schwartzian transform:
use warnings;
use strict;
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' );
@list = map { $_->[0] }
sort { $a->[1] cmp $b->[1] or $a->[2] <=> $b->[2] }
map { [$_, split /-/] }
@list;
for (@list) {
print($_."\n");
}
打印:
group1-1
group1-2
group1-9
group1-10
group2-1
group2-2
group2-9
group2-10
这里的数据有一些细节可能会导致一个安静的错误。当您使用连字符前的子字符串进行排序时(group1
等),它有两个字母 和 数字,因此当按字典顺序排序时,多位数可能是错误的。例如
group1, group2, group10
被sort
-ed(默认情况下cmp
)为
group1
group10
group2
我猜怎么了。
所以在排序中我们需要将groupN
分解为group
和N
,并按N
.
进行数字排序
use warnings;
use strict;
use feature 'say';
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9',
'group1-10', 'group2-10',
'group10-2', 'group10-1' # Added some 'group10' data
);
# Break input string into: group N - N (and sort by first then second number)
@list =
map { $_->[0] }
sort { $a->[2] <=> $b->[2] or $a->[4] <=> $b->[4] }
map { [ $_, /[0-9]+|[a-zA-Z]+|\-/g ] }
@list;
say for @list;
正则表达式从字符串中提取数字和单词,用于排序。但是如果那个单独的子字符串总是确实相同 (group
) 那么我们只能按数字排序并且可以使用 /[0-9]+/g
,并比较索引 1
和 [=21= 处的数组引用元素的数值].
版画
group1-1
group1-2
group1-9
group1-10
group2-1
group2-2
group2-9
group2-10
group10-1
group10-2
自然排序
你想要的是所谓的“自然排序”。
use Sort::Key::Natural qw( natsort );
my @sorted = natsort @unsorted;
也可以就地执行。
use Sort::Key::Natural qw( natsort_inplace );
natsort_inplace @array;
键排序
当您需要更多控制时。
use Sort::Key::Multi qw( uukeysort );
my @sorted = uukeysort { /(\d+)/g } @unsorted;
或
use Sort::Key::Multi qw( uukeysort_inplace );
uukeysort_inplace { /(\d+)/g } @array;
没有模块(未优化)
my @sorted =
sort {
my ($ag, $an) = $a =~ /(\d+)/g;
my ($bg, $bn) = $b =~ /(\d+)/g;
$ag <=> $bg || $an <=> $bn
}
@unsorted;
没有模块(施瓦兹变换)
这样可以避免重复同样的工作。它没有提取信息 2*N*log2(N) 次,而是只提取了 N 次。
my @sorted =
map $_->[0],
sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }
map [ $_, /(\d+)/g ],
@unsorted;
没有模块 (GRT)
ST的优化
my @sorted =
map substr($_->[0], 8),
sort
map pack('NNa*', /(\d+)/g, $_),
@unsorted;
我有一个字符串列表,格式如下:
('group1-1', 'group1-2','group1-9', 'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' )
我需要按如下方式排序:
先分组,再分组。
('group1-1', 'group1-2','group1-9','group1-10', 'group2-1','group2-2', 'group2-9', 'group2-10' )
我编写了以下代码,但没有按预期运行: 一个根据组排序的比较器,如果组匹配,它根据数字排序。
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' );
@list = sort compare @list;
for (@list){
print($_."\n");
}
sub compare{
my $first_group, $first_num = get_details($a);
my $second_group, $second_num = get_details($b);
if($first_group < $second_group){
return -1;
} elsif($first_group == $second_group){
if ( $first_num < $second_num) {
return -1;
} elsif ( $first_num == $second_num ) {
return 0;
} else {
return 1;
}
} else{
return 1;
}
}
sub get_details($){
my $str= shift;
my $group = (split /-/, $str)[0];
$group =~ s/\D//g;
my $num = (split /-/, $str)[1];
$num =~ s/\D//g;
return $group, $num;
}
我会确保列表中的字符串遵循模式 (\S+\d+-\d+
),然后使用 cmp
作为字符串比较部分,使用 <=>
作为数字:
sub compare {
if( $a =~ /(\S+)(\d+)-(\d+)/ ) {
my($A1,$A2,$A3) = (,,);
if( $b =~ /(\S+)(\d+)-(\d+)/ ) {
my($B1,$B2,$B3) = (,,);
return ($A1 cmp $B1) || ($A2 <=> $B2) || $A3 <=> $B3;
}
}
$a cmp $b; # fallback if a string doesn't follow the pattern
};
您可以使用 Schwartzian transform:
use warnings;
use strict;
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9','group1-10', 'group2-10' );
@list = map { $_->[0] }
sort { $a->[1] cmp $b->[1] or $a->[2] <=> $b->[2] }
map { [$_, split /-/] }
@list;
for (@list) {
print($_."\n");
}
打印:
group1-1
group1-2
group1-9
group1-10
group2-1
group2-2
group2-9
group2-10
这里的数据有一些细节可能会导致一个安静的错误。当您使用连字符前的子字符串进行排序时(group1
等),它有两个字母 和 数字,因此当按字典顺序排序时,多位数可能是错误的。例如
group1, group2, group10
被sort
-ed(默认情况下cmp
)为
group1 group10 group2
我猜怎么了。
所以在排序中我们需要将groupN
分解为group
和N
,并按N
.
use warnings;
use strict;
use feature 'say';
my @list = ('group1-1', 'group1-2','group1-9',
'group2-1','group2-2', 'group2-9',
'group1-10', 'group2-10',
'group10-2', 'group10-1' # Added some 'group10' data
);
# Break input string into: group N - N (and sort by first then second number)
@list =
map { $_->[0] }
sort { $a->[2] <=> $b->[2] or $a->[4] <=> $b->[4] }
map { [ $_, /[0-9]+|[a-zA-Z]+|\-/g ] }
@list;
say for @list;
正则表达式从字符串中提取数字和单词,用于排序。但是如果那个单独的子字符串总是确实相同 (group
) 那么我们只能按数字排序并且可以使用 /[0-9]+/g
,并比较索引 1
和 [=21= 处的数组引用元素的数值].
版画
group1-1 group1-2 group1-9 group1-10 group2-1 group2-2 group2-9 group2-10 group10-1 group10-2
自然排序
你想要的是所谓的“自然排序”。
use Sort::Key::Natural qw( natsort );
my @sorted = natsort @unsorted;
也可以就地执行。
use Sort::Key::Natural qw( natsort_inplace );
natsort_inplace @array;
键排序
当您需要更多控制时。
use Sort::Key::Multi qw( uukeysort );
my @sorted = uukeysort { /(\d+)/g } @unsorted;
或
use Sort::Key::Multi qw( uukeysort_inplace );
uukeysort_inplace { /(\d+)/g } @array;
没有模块(未优化)
my @sorted =
sort {
my ($ag, $an) = $a =~ /(\d+)/g;
my ($bg, $bn) = $b =~ /(\d+)/g;
$ag <=> $bg || $an <=> $bn
}
@unsorted;
没有模块(施瓦兹变换)
这样可以避免重复同样的工作。它没有提取信息 2*N*log2(N) 次,而是只提取了 N 次。
my @sorted =
map $_->[0],
sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }
map [ $_, /(\d+)/g ],
@unsorted;
没有模块 (GRT)
ST的优化
my @sorted =
map substr($_->[0], 8),
sort
map pack('NNa*', /(\d+)/g, $_),
@unsorted;