2012-05-20 148 views
5

我正在寻找按这种格式排序的逻辑(不是附加模块)。我有一个字符串列表,它看起来像:按mmyy(月份和年份)排序

asdadasBBBsfasdasdas-0112 
asdanfnfnfnfnf222ads-1210 

等 我不能只是排序的数字,因为,例如:812> 113(812 = 2012年8月,113 = 2013年1月,所以其不正确)

有什么好的策略?

感谢,

回答

5

一个的Schwartzian转换将在这里是一个巨大的浪费。这个类似的名字我永远不会记得的名字会更好。

my @sorted = 
    map substr($_, 4), 
    sort 
    map substr($_, -2) . substr($_, -4, 2) . $_, 
     @unsorted; 

使用匹配运算符,而不是substr

my @sorted = 
    map substr($_, 4), 
    sort 
    map { /(..)(..)\z/s; $2.$1.$_ } 
     @unsorted; 
+2

[Guttman Rosler Transform](http://www.perlmonks.org/?node_id=145659) –

+1

对于我从10到200k的数组大小运行的基准测试,GRT比ST或天真实施快2-5倍。 –

+0

Benchmark [性能](http://i.imgur.com/LSFtm.png),[code](https://gist.github.com/2764370) –

2

使用排序功能,看上去在今年第一,然后日期:

sub mmyy_sorter { 

    my $a_yy = substr($a, -2); 
    my $b_yy = substr($b, -2); 

    my $a_mm = substr($a, -4, 2); 
    my $b_mm = substr($b, -4, 2); 

    return ($a_yy cmp $b_yy) || ($a_mm cmp $b_mm); 
} 

my @sorted = sort mmyy_sorter @myarray; 

注:这是技术上效率不高,因为它可能是因为它重新计算每个比较的月份和年份子字段,而不是仅针对数组中的每个项目。

也可以利用Perl的自动类型转换,并使用<=>运算符代替cmp,因为所有值实际上都代表数字。

+0

计算子便宜。你有没有基准测试与完整的Schwartzian变换? –

+0

@GregBacon我还没有,但我不希望有任何实质性的差异,直到击中1000+条目。 – Alnitak

+0

我已更正了妨碍排序例程正确排序的错字。 – pilcrow

0

怎么样把它重制成几个月?例如:

812 = 12 * 12 + 8

113 = 13 * 12 + 1

你可以把年后几个月,这将是很好的。为了选择数字,你可以使用正则表达式。

5

如何Schwartzian transform

#!/usr/bin/perl 
use strict; 
use warnings; 
use Data::Dump qw(dump); 

my @list = (
    'asdadasBBBsfasdasdas-0112', 
    'asdanfnfnfnfnf222ads-1210', 
    'asdanfnfnfnfnf222ads-1211', 
    'asdanfnfnfnfnf222ads-1010', 
    'asdanfnfnfnfnf222ads-1011', 
); 

my @sorted = 
    map { $_->[0] } 
    sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] } 
    map { /-(\d\d)(\d\d)$/; [$_, $2, $1] } @list; 
dump @sorted; 

输出:

(
    "asdanfnfnfnfnf222ads-1010", 
    "asdanfnfnfnfnf222ads-1210", 
    "asdanfnfnfnfnf222ads-1011", 
    "asdanfnfnfnfnf222ads-1211", 
    "asdadasBBBsfasdasdas-0112", 
) 
+1

使用Schwartzian变换的完美方式+1。我自己会使用'$ _-> [2]'而不是'splice' tho。 – dgw

+1

当我使用ST时,我总是把字符串放在'$ _-> [0]'中。这样,顶层地图总是'map $ _-> [0],'。在这种情况下,底部会简化为'map [$ _,/(..)(...../z/s],'。 – ikegami

0

感谢@ M42的样本数据。

use strict; 
use warnings; 
use feature 'say'; 

my @list = (
    'asdadasBBBsfasdasdas-0112', 
    'asdanfnfnfnfnf222ads-1210', 
    'asdanfnfnfnfnf222ads-1211', 
    'asdanfnfnfnfnf222ads-1010', 
    'asdanfnfnfnfnf222ads-1011', 
); 

my @sorted = sort { 
    my ($aa, $bb) = map { /(..)(..)\z/ and $2.$1 } $a, $b; 
    $aa <=> $bb; 
} @list; 

say for @sorted; 

输出

asdanfnfnfnfnf222ads-1010 
asdanfnfnfnfnf222ads-1210 
asdanfnfnfnfnf222ads-1011 
asdanfnfnfnfnf222ads-1211 
asdadasBBBsfasdasdas-0112