当月的日期跨越当月末到下月初时,如何重新排列月的日期
How to rearrange dates of the month when they span across end of current month to beginning of next month
我必须处理根据月份日期变化的数据。当我从文件名中提取日期时,我得到了日期的随机排列,如下所示。
31 02 28 30 27 01 29 03 04
这是在处理从 8 月 27 日到 9 月 4 日的数据。我需要从 27 日到 4 日按顺序排列的日期。我必须一次处理 9 个日期。这个问题出现在月底,当时我有这个月的日期(大数字)和下个月的日期(小数字)。所以我对数组进行排序,我称之为@fdaylist。我得到
01 02 03 04 27 28 29 30 31.
为了得到我想要的下面的脚本片段,完成工作并给出
27 28 29 30 31 01 02 03 04
我确定这个脚本是否可以一直运行。它多次重现序列,所以我必须使用 uniq() 函数。
如果我能得到有关实现 objective.
的更好方法的建议,我将不胜感激
my $last_occ=lastidx { /0\d/ } @fdaylist;
if($last_occ > 1){
foreach(@fdaylist){
for(my $mm=$last_occ+1; $mm < @fdaylist; ++$mm){
push (@fday, $fdaylist[$mm]);
}
for(my $nn=0; $nn <= $last_occ; ++$nn){
push (@fday, $fdaylist[$nn]);
}
}
}
@fday = uniq(@fday);
请查看以下示例代码是否执行您在 post 中描述的操作。
代码:
- 将日期读入字符串
- 拆分字符串并将日期排序到数组中
- 查找以
0\d
开头的最后一天的索引
- 用两个数组切片重新排列数组
注意:打印出输入、排序和重新排序的数据
use strict;
use warnings;
use feature 'say';
while( <DATA> ) {
chomp;
say 'GOT: ' . $_;
my @dates = sort split ' ', $_;
say 'IN: ' . join(' ',@dates);
my $index = -1;
/0\d/ && $index++ for @dates;
@dates = (@dates[$index+1..$#dates],@dates[0..$index]);
say 'OUT: ' . join(' ', @dates);
say '-' x 45;
}
__DATA__
31 02 28 30 27 01 29 03 04
28 03 26 02 25 01 23 22 24
输出
GOT: 31 02 28 30 27 01 29 03 04
IN: 01 02 03 04 27 28 29 30 31
OUT: 27 28 29 30 31 01 02 03 04
---------------------------------------------
GOT: 28 03 26 02 25 01 23 22 24
IN: 01 02 03 22 23 24 25 26 28
OUT: 22 23 24 25 26 28 01 02 03
---------------------------------------------
我假设数字必须是连续的,有一个空位,否则无法确定某些数字属于哪一列。我还假设总是存在差距。†(不。虽然日期确实是连续的,但它们可能跨越两个月 或 在一个月内,已澄清。)
一种方法:遍历排序数组,从前到后移动项目,直到到达间隙
use warnings;
use strict;
use feature 'say';
# Dates are consecutive, either straddling two months or within a month
my @dates = (31, 02, 28, 30, 27, 01, 29, 03, 04); # or can be 05..13 etc
@dates = sort { $a <=> $b } @dates;
if (consec_nums(\@dates)) {
say "Consecutive numbers (dates in same month), nothing to do (@dates)";
}
else {
my $last_moved;
while (1) {
push @dates, $last_moved = shift @dates;
last if $dates[0] > $last_moved+1;
}
@dates = map { sprintf "%02d", $_ } @dates; # for 01 02 etc
}
say "@dates";
# Returns true (1) if numbers are consecutive, like consecutive dates
# in a single month, false (undef) otherwise. Assumes a sorted array
sub consec_nums {
my ($ra) = @_;
my $prev = $ra->[0];
for my $i (1..$#$ra) {
return if $ra->[$i] > $prev+1;
$prev = $ra->[$i];
}
return 1;
}
另一种方法:遍历排序后的数组,找到间隙之前的最后一个索引(之后数字不再连续);然后拼接推入
# same sorted @dates, same assumptions. same consec_nums() sub
if (consec_nums(\@dates)) {
say "Consecutive numbers (dates in same month), nothing to do (@dates)";
}
else {
my $consec_idx;
for my $i (0 .. $#dates) {
$consec_idx = $i, last
if $dates[$i]+1 < $dates[$i+1];
}
push @dates, splice @dates, 0, $consec_idx+1;
}
say "@dates";
† 对于上述假设:
如果我们可以有1 2 10 30 31
那么应该是10 30 31 1 2
还是30 31 1 2 10
?
如果没有间隔(一个月内的所有日期),如 05 .. 13
,那么上述过程将中断。如果可能出现这种情况,那么首先对其进行测试。
已经在评论中说明确实可以,所有日期都在一个月内。上面的答案已经通过针对这种情况的测试进行了修改。
我必须处理根据月份日期变化的数据。当我从文件名中提取日期时,我得到了日期的随机排列,如下所示。
31 02 28 30 27 01 29 03 04
这是在处理从 8 月 27 日到 9 月 4 日的数据。我需要从 27 日到 4 日按顺序排列的日期。我必须一次处理 9 个日期。这个问题出现在月底,当时我有这个月的日期(大数字)和下个月的日期(小数字)。所以我对数组进行排序,我称之为@fdaylist。我得到
01 02 03 04 27 28 29 30 31.
为了得到我想要的下面的脚本片段,完成工作并给出
27 28 29 30 31 01 02 03 04
我确定这个脚本是否可以一直运行。它多次重现序列,所以我必须使用 uniq() 函数。 如果我能得到有关实现 objective.
的更好方法的建议,我将不胜感激my $last_occ=lastidx { /0\d/ } @fdaylist;
if($last_occ > 1){
foreach(@fdaylist){
for(my $mm=$last_occ+1; $mm < @fdaylist; ++$mm){
push (@fday, $fdaylist[$mm]);
}
for(my $nn=0; $nn <= $last_occ; ++$nn){
push (@fday, $fdaylist[$nn]);
}
}
}
@fday = uniq(@fday);
请查看以下示例代码是否执行您在 post 中描述的操作。
代码:
- 将日期读入字符串
- 拆分字符串并将日期排序到数组中
- 查找以
0\d
开头的最后一天的索引
- 用两个数组切片重新排列数组
注意:打印出输入、排序和重新排序的数据
use strict;
use warnings;
use feature 'say';
while( <DATA> ) {
chomp;
say 'GOT: ' . $_;
my @dates = sort split ' ', $_;
say 'IN: ' . join(' ',@dates);
my $index = -1;
/0\d/ && $index++ for @dates;
@dates = (@dates[$index+1..$#dates],@dates[0..$index]);
say 'OUT: ' . join(' ', @dates);
say '-' x 45;
}
__DATA__
31 02 28 30 27 01 29 03 04
28 03 26 02 25 01 23 22 24
输出
GOT: 31 02 28 30 27 01 29 03 04
IN: 01 02 03 04 27 28 29 30 31
OUT: 27 28 29 30 31 01 02 03 04
---------------------------------------------
GOT: 28 03 26 02 25 01 23 22 24
IN: 01 02 03 22 23 24 25 26 28
OUT: 22 23 24 25 26 28 01 02 03
---------------------------------------------
我假设数字必须是连续的,有一个空位,否则无法确定某些数字属于哪一列。我还假设总是存在差距。†(不。虽然日期确实是连续的,但它们可能跨越两个月 或 在一个月内,已澄清。)
一种方法:遍历排序数组,从前到后移动项目,直到到达间隙
use warnings;
use strict;
use feature 'say';
# Dates are consecutive, either straddling two months or within a month
my @dates = (31, 02, 28, 30, 27, 01, 29, 03, 04); # or can be 05..13 etc
@dates = sort { $a <=> $b } @dates;
if (consec_nums(\@dates)) {
say "Consecutive numbers (dates in same month), nothing to do (@dates)";
}
else {
my $last_moved;
while (1) {
push @dates, $last_moved = shift @dates;
last if $dates[0] > $last_moved+1;
}
@dates = map { sprintf "%02d", $_ } @dates; # for 01 02 etc
}
say "@dates";
# Returns true (1) if numbers are consecutive, like consecutive dates
# in a single month, false (undef) otherwise. Assumes a sorted array
sub consec_nums {
my ($ra) = @_;
my $prev = $ra->[0];
for my $i (1..$#$ra) {
return if $ra->[$i] > $prev+1;
$prev = $ra->[$i];
}
return 1;
}
另一种方法:遍历排序后的数组,找到间隙之前的最后一个索引(之后数字不再连续);然后拼接推入
# same sorted @dates, same assumptions. same consec_nums() sub
if (consec_nums(\@dates)) {
say "Consecutive numbers (dates in same month), nothing to do (@dates)";
}
else {
my $consec_idx;
for my $i (0 .. $#dates) {
$consec_idx = $i, last
if $dates[$i]+1 < $dates[$i+1];
}
push @dates, splice @dates, 0, $consec_idx+1;
}
say "@dates";
† 对于上述假设:
如果我们可以有
1 2 10 30 31
那么应该是10 30 31 1 2
还是30 31 1 2 10
?如果没有间隔(一个月内的所有日期),如
05 .. 13
,那么上述过程将中断。如果可能出现这种情况,那么首先对其进行测试。已经在评论中说明确实可以,所有日期都在一个月内。上面的答案已经通过针对这种情况的测试进行了修改。