2012-05-20 26 views
5

Estoy buscando un módulo lógico (no adicional) para ordenar por dicho formato. Tengo una lista de cadenas que se parece a:clasificación por mmyy (mes y año)

asdadasBBBsfasdasdas-0112 
asdanfnfnfnfnf222ads-1210 

etc. no puedo simplemente ordenar por los números, porque, por ejemplo: 812> 113 (812 = Agosto de 2012, 113 = enero de 2013, por lo que su incorrecta)

¿Alguna buena estrategia?

gracias,

Respuesta

5

Un schwartzian transformar sería un enorme desperdicio aquí. Este constructo similar cuyo nombre nunca podré recordar sería mucho mejor.

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

utilización del operador de juego en lugar de 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

Para los benchmarks encontré tamaños de matriz de 10 a 200k, GRT era 2-5 veces más rápido que las implementaciones ST o ingenuas. –

+0

Benchmark [rendimiento] (http://i.imgur.com/LSFtm.png), [código] (https://gist.github.com/2764370) –

2

utilizar una función de clasificación que se ve en el primer año, y después de la fecha:

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; 

NB: esto es técnicamente no es tan eficiente como podría ser, ya que tiene para volver a calcular los subcampos de mes y año para cada comparación, no solo una vez para cada elemento en la matriz.

También sería posible aprovechar la conversión de tipo automática de Perl y usar el operador <=> en lugar de cmp, ya que todos los valores realmente representan números.

+0

subseries Informática es barato. ¿Ha comparado una Transformada Schwartziana completa? –

+0

@GregBacon No lo he hecho, pero no esperaría ninguna diferencia importante en el rendimiento hasta llegar a más de 1000 entradas. – Alnitak

+0

He corregido el error tipográfico que impedía que su rutina de clasificación se clasificara correctamente. – pilcrow

0

¿Qué hay de remake it to months? Por ejemplo:

812 = 12 * 12 + 8

113 = 13 * 12 + 1

Puede girar años en meses y va a ser buena. Para seleccionar números, puede usar expresiones regulares.

5

¿Qué tal 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; 

de salida:

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

+1 para la forma perlista usando una transformación de Schwartz. Yo mismo habría usado '$ _-> [2]' en lugar del 'splice' tho. – dgw

+1

Siempre coloco la cadena en '$ _-> [0]' cuando uso ST. De esta forma, el mapa superior siempre es 'map $ _-> [0],'. En este caso, la parte inferior se simplificaría a 'map [$ _, /(..)(..)\z/s],'. – ikegami

0

Gracias a @ M42 para los datos de la muestra.

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; 

salida

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