使用 Perl 对具有特定字母顺序的字符串进行排序
Sort strings with a specific letter order with Perl
我正在尝试使用 Perl 以特定字母顺序对名称列表进行排序以执行某些特殊功能。
排序方式与 sort { $a cmp $b }
相同,但字母顺序不同。
例如,以任意字符顺序排序 "abdrtwsuiopqe987654" ...
我尝试处理 sort { $a myFunction $b }
但我是 Perl 的新手,我不知道如何正确组织 myFunction
以获得我想要的东西。
- 是否有提供此功能的特定功能(包)?
- 您有处理字符串的自定义排序函数的示例吗?
- 您知道
cmp
函数是如何(或在哪个源文件中)用 Perl 实现的,看看它是如何工作的吗?
以下可能是最快的[1]:
sub my_compare($$) {
$_[0] =~ tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r
cmp
$_[1] =~ tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r
}
my @sorted = sort my_compare @unsorted;
或者如果您想要更动态的东西,以下可能是最快的[2]:
my @syms = split //, 'abdrtwsuiopqe987654';
my @map; $map[ord($syms[$_])] = $_ for 0..$#syms;
sub my_compare($$) {
(pack 'C*', map $map[ord($_)], unpack 'C*', $_[0])
cmp
(pack 'C*', map $map[ord($_)], unpack 'C*', $_[1])
}
my @sorted = sort my_compare @unsorted;
我们可以逐个字符地进行比较,但这会远慢。
use List::Util qw( min );
my @syms = split //, 'abdrtwsuiopqe987654';
my @map; $map[ord($syms[$_])] = $_ for 0..$#syms;
sub my_compare($$) {
my $l0 = length($_[0]);
my $l1 = length($_[1]);
for (0..min($l0, $l1)) {
my $ch0 = $map[ord(substr($_[0], $_, 1))];
my $ch1 = $map[ord(substr($_[1], $_, 1))];
return -1 if $ch0 < $ch1;
return +1 if $ch0 > $ch1;
}
return -1 if $l0 < $l1;
return +1 if $l0 > $l1;
return 0;
}
my @sorted = sort my_compare @unsorted;
从技术上讲,使用 GRT 可以使其更快。
my @sorted =
map /[=13=](.*)/s,
sort
map { tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r . "[=13=]" . $_ }
@unsorted;
从技术上讲,使用 GRT 可以使其更快。
my @sorted =
map /[=14=](.*)/s,
sort
map { ( pack 'C*', map $map[ord($_)], unpack 'C*', $_ ) . "[=14=]" . $_ }
@unsorted;
cmp
由 scmp
运算符实现。
$ perl -MO=Concise,-exec -e'$x cmp $y'
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <#> gvsv[*x] s
4 <#> gvsv[*y] s
5 <2> scmp[t3] vK/2
6 <@> leave[1 ref] vKP/REFC
scmp
运算符由 pp.c
, which is really just a wrapper for sv_cmp_flags
in sv.c
when use locale;
isn't in effect. sv_cmp_flags
either uses C library function memcmp
中的 pp_scmp
函数或支持 UTF-8 的版本(取决于标量类型)实现。
use Sort::Key qw(keysort);
my @sorted = keysort { tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/r } @data;
或者在不支持 tr/.../.../r
中的 r
标志的旧 perls 中
my @sorted = keysort { my $key = $_;
$key =~ tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/;
$key } @data;
您还可以为此类数据创建专门的排序子例程,如下所示:
use Sort::Key::Maker 'my_special_sort',
sub { tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/r },
qw(string);
my @sorted = my_special_sort @data;
my @sorted2 = my_special_sort @data2;
我正在尝试使用 Perl 以特定字母顺序对名称列表进行排序以执行某些特殊功能。
排序方式与 sort { $a cmp $b }
相同,但字母顺序不同。
例如,以任意字符顺序排序 "abdrtwsuiopqe987654" ...
我尝试处理 sort { $a myFunction $b }
但我是 Perl 的新手,我不知道如何正确组织 myFunction
以获得我想要的东西。
- 是否有提供此功能的特定功能(包)?
- 您有处理字符串的自定义排序函数的示例吗?
- 您知道
cmp
函数是如何(或在哪个源文件中)用 Perl 实现的,看看它是如何工作的吗?
以下可能是最快的[1]:
sub my_compare($$) {
$_[0] =~ tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r
cmp
$_[1] =~ tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r
}
my @sorted = sort my_compare @unsorted;
或者如果您想要更动态的东西,以下可能是最快的[2]:
my @syms = split //, 'abdrtwsuiopqe987654';
my @map; $map[ord($syms[$_])] = $_ for 0..$#syms;
sub my_compare($$) {
(pack 'C*', map $map[ord($_)], unpack 'C*', $_[0])
cmp
(pack 'C*', map $map[ord($_)], unpack 'C*', $_[1])
}
my @sorted = sort my_compare @unsorted;
我们可以逐个字符地进行比较,但这会远慢。
use List::Util qw( min );
my @syms = split //, 'abdrtwsuiopqe987654';
my @map; $map[ord($syms[$_])] = $_ for 0..$#syms;
sub my_compare($$) {
my $l0 = length($_[0]);
my $l1 = length($_[1]);
for (0..min($l0, $l1)) {
my $ch0 = $map[ord(substr($_[0], $_, 1))];
my $ch1 = $map[ord(substr($_[1], $_, 1))];
return -1 if $ch0 < $ch1;
return +1 if $ch0 > $ch1;
}
return -1 if $l0 < $l1;
return +1 if $l0 > $l1;
return 0;
}
my @sorted = sort my_compare @unsorted;
从技术上讲,使用 GRT 可以使其更快。
my @sorted = map /[=13=](.*)/s, sort map { tr{abdrtwsuiopqe987654}{abcdefghijklmnopqrs}r . "[=13=]" . $_ } @unsorted;
从技术上讲,使用 GRT 可以使其更快。
my @sorted = map /[=14=](.*)/s, sort map { ( pack 'C*', map $map[ord($_)], unpack 'C*', $_ ) . "[=14=]" . $_ } @unsorted;
cmp
由 scmp
运算符实现。
$ perl -MO=Concise,-exec -e'$x cmp $y'
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <#> gvsv[*x] s
4 <#> gvsv[*y] s
5 <2> scmp[t3] vK/2
6 <@> leave[1 ref] vKP/REFC
scmp
运算符由 pp.c
, which is really just a wrapper for sv_cmp_flags
in sv.c
when use locale;
isn't in effect. sv_cmp_flags
either uses C library function memcmp
中的 pp_scmp
函数或支持 UTF-8 的版本(取决于标量类型)实现。
use Sort::Key qw(keysort);
my @sorted = keysort { tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/r } @data;
或者在不支持 tr/.../.../r
r
标志的旧 perls 中
my @sorted = keysort { my $key = $_;
$key =~ tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/;
$key } @data;
您还可以为此类数据创建专门的排序子例程,如下所示:
use Sort::Key::Maker 'my_special_sort',
sub { tr/abdrtwsuiopqe987654/abcdefghijklmnopqrs/r },
qw(string);
my @sorted = my_special_sort @data;
my @sorted2 = my_special_sort @data2;