如何解决perl使用数组对子字符串进行排序以确定排序顺序
我有以下形式的字符串列表:
CLUB1_20201008_EVE
CLUB1_20201008_AFT
CLUB1_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_PM
CLUB1_20201008_NIGHT
CLUB2_20201008_EVE
CLUB2_20201008_AFT
CLUB2_20201008_AM
CLUB2_20201008_AM2
CLUB2_20201008_PM
CLUB2_20201008_NIGHT
我可以按俱乐部名称和日期进行排序,但是一天中的时间需要像AM,AM2,AFT,PM,EVE,NIGHT
那样进行排序。这些显然是无法排序的,因为它们的顺序不是字母顺序的。
如何使用辅助数组使它们按正确的顺序排序?
谢谢,牛奶
预期输出 CLUB1_20201008_NIGHT CLUB2_20201008_NIGHT CLUB1_20201008_EVE CLUB2_20201008_EVE CLUB1_20201008_PM CLUB2_20201008_PM CLUB1_20201008_AFT CLUB2_20201008_AFT CLUB1_20201008_AM2 CLUB2_20201008_AM2 CLUB1_20201008_AM CLUB2_20201008_AM
解决方法
一种方法是使用哈希表将字符串映射到其数字顺序,然后基于该哈希表进行比较:
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say state/;
my @clubs = qw/CLUB1_20201008_EVE CLUB1_20201008_AFT CLUB1_20201008_AM
CLUB1_20201008_AM2 CLUB1_20201008_PM CLUB1_20201008_NIGHT
CLUB2_20201008_EVE CLUB2_20201008_AFT CLUB2_20201008_AM
CLUB1_20201008_AM2 CLUB1_20201008_PM CLUB1_20201008_NIGHT/;
sub sort_clubs {
state $mappings = { AM => 1,AM2 => 2,AFT => 3,PM => 4,EVE => 5,NIGHT => 6 };
# For use with a Schwartzian Transform of the original data.
# Expected format of arguments: [ [ club name,date,time ],original string ]
my $cmp = $a->[0][0] cmp $b->[0][0];
if ($cmp != 0) {
return $cmp;
}
$cmp = $a->[0][1] <=> $b->[0][1];
if ($cmp != 0) {
return $cmp;
} else {
return $mappings->{$a->[0][2]} <=> $mappings->{$b->[0][2]}
}
}
@clubs = map { $_->[1] } sort sort_clubs map { [ [ split(/_/,$_) ],$_ ] } @clubs;
say "@clubs";
如果您以前没有看到过用于排序的惯用语,则维基百科提供有关Schwartzian Transform的信息。
,诀窍是在每个时间字符串和您可以排序的数字之间创建映射。
C:\Programming\Projects\ExampleSolution\ExampleProject\Uploads\
基于that's not guaranteed的解决方案将是最干净,最快的解决方案。
var/www/ExampleProject/Uploads
不带模块的简单解决方案:
my @shifts = qw( AM AM2 AFT PM EVE NIGHT );
my %shift_order = map { $shifts[$_] => $_ } 0..$#shifts;
不带模块的高性能解决方案:
use Sort::Key::Multi qw( ssukeysort );
my @shifts = qw( AM AM2 AFT PM EVE NIGHT );
my %shift_order = map { $shifts[$_] => $_ } 0..$#shifts;
my @sorted =
ssukeysort {
my ($club,$date,$shift) = split /_/;
( $club,$shift_order{$shift} )
}
@unsorted;
,
有很多方法可以达到预期的效果。
注意:假定您未尝试在俱乐部,date_hour_min和day_time上进行排序,因为代码未在您的问题中声明。所需的排序输出样本将有助于解决您的问题-我们无法理解您的想法。
请研究以下两种可能的方法。
您已根据字符串中的时间索引声明了排序顺序-让它以某种方式使用。为了简单起见,我将使用AM,AM2,AFT,PM,EVE,NIGHT
作为初始化字符串。
第一种方法使用%order
哈希,其中时间日期是表示数字顺序的键和数字。以数字顺序作为键存储在HoA中的字符串。填充完哈希后,只需按照数字键顺序打印行,并保留其在输入中的出现顺序即可。
use strict;
use warnings;
use feature 'say';
my $count = 0;
my @set = split ',','AM,NIGHT';
my %order = map { $_ => $count++ } @set;
my %result;
while( <DATA> ) {
chomp;
for my $k ( keys %order ) {
push @{$result{$order{$k}}},$_ if /_$k\z/;
}
}
for( sort {$a <=> $b} keys %result ) {
say for @{ $result{$_} };
}
__DATA__
CLUB1_20201008_EVE
CLUB1_20201008_AFT
CLUB1_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_PM
CLUB1_20201008_NIGHT
CLUB2_20201008_EVE
CLUB2_20201008_AFT
CLUB2_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_PM
CLUB1_20201008_NIGHT
输出
CLUB1_20201008_AM
CLUB2_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_AM2
CLUB1_20201008_AFT
CLUB2_20201008_AFT
CLUB1_20201008_PM
CLUB1_20201008_PM
CLUB1_20201008_EVE
CLUB2_20201008_EVE
CLUB1_20201008_NIGHT
CLUB1_20201008_NIGHT
第二种方法更加简单。根据 time day 索引(在行末)在HoA %result
中插入行。然后根据预定义的$order
数组打印打印HoA。
use strict;
use warnings;
use feature 'say';
my @order = split ',NIGHT';
my %result;
while( <DATA> ) {
chomp;
push @{$result{$1}},$_ if /_([^_]+)\z/;
}
for( @order ) {
say for @{ $result{$_} };
}
__DATA__
CLUB1_20201008_EVE
CLUB1_20201008_AFT
CLUB1_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_PM
CLUB1_20201008_NIGHT
CLUB2_20201008_EVE
CLUB2_20201008_AFT
CLUB2_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_PM
CLUB1_20201008_NIGHT
输出
CLUB1_20201008_AM
CLUB2_20201008_AM
CLUB1_20201008_AM2
CLUB1_20201008_AM2
CLUB1_20201008_AFT
CLUB2_20201008_AFT
CLUB1_20201008_PM
CLUB1_20201008_PM
CLUB1_20201008_EVE
CLUB2_20201008_EVE
CLUB1_20201008_NIGHT
CLUB1_20201008_NIGHT
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。