2012-05-20 41 views
5

Tôi đang tìm một mô-đun logic (không phải mô-đun bổ sung) để sắp xếp theo định dạng như vậy. Tôi có một danh sách các chuỗi trông giống như:sắp xếp theo mmyy (tháng và năm)

asdadasBBBsfasdasdas-0112 
asdanfnfnfnfnf222ads-1210 

, vv tôi không thể chỉ sắp xếp theo các con số, bởi vì, ví dụ: 812> 113 (812 = Tháng Tám 2012, 113 = tháng Giêng năm 2013, vì vậy không chính xác của nó)

bất kỳ chiến lược nào tốt?

cảm ơn,

Trả lời

5

Một schwartzian chuyển đổi sẽ là một sự lãng phí rất lớn ở đây. Cấu trúc tương tự này có tên tôi không bao giờ có thể nhớ sẽ là cách tốt hơn.

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

Sử dụng các nhà điều hành trận đấu thay vì 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

Đối với điểm chuẩn tôi chạy qua các kích thước mảng từ 10 đến 200k, GRT nhanh hơn 2-5 lần so với triển khai ST hoặc ngây thơ. –

+0

Điểm chuẩn [hiệu suất] (http://i.imgur.com/LSFtm.png), [mã] (https://gist.github.com/2764370) –

2

Sử dụng chức năng sắp xếp mà nhìn vào năm đầu tiên, và sau đó ngày:

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: đây là kỹ thuật không hiệu quả như nó có thể là vì nó có để tính toán lại các trường con tháng và năm cho mỗi lần so sánh, không chỉ một lần cho mỗi mục trong mảng.

Cũng có thể tận dụng lợi thế của chuyển đổi loại tự động của Perl và sử dụng toán tử <=> thay cho cmp, vì tất cả các giá trị thực sự đại diện cho các số.

+0

chuỗi con Computing là giá rẻ. Bạn đã đo điểm chuẩn so với Chuyển đổi Schwartzian đầy đủ chưa? –

+0

@GregBacon Tôi đã không, nhưng tôi sẽ không mong đợi bất kỳ sự khác biệt về hiệu suất vật liệu cho đến khi đạt 1000 mục. – Alnitak

+0

Tôi đã sửa lỗi đánh máy đã ngăn không cho sắp xếp của bạn được sắp xếp một cách chính xác. – pilcrow

0

Điều gì về việc làm lại thành tháng? Ví dụ:

812 = 12 * 12 + 8

113 = 13 * 12 + 1

Bạn có thể bật năm vào tháng và nó sẽ được tốt. Để chọn số bạn có thể sử dụng regex.

5

Làm thế nào về 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; 

đầu ra:

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

+1 cho cách thông thường bằng cách sử dụng phép biến đổi Schwartz. Bản thân tôi đã sử dụng '$ _-> [2]' thay vì 'splice' tho. – dgw

+1

Tôi luôn đặt chuỗi trong '$ _-> [0]' khi tôi sử dụng ST. Bằng cách đó, bản đồ trên cùng luôn luôn là 'map $ _-> [0],'. Trong trường hợp này, phần dưới sẽ đơn giản hóa thành 'map [$ _, /(..)(..)\z/s],'. – ikegami

0

Nhờ @ M42 cho dữ liệu mẫu.

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; 

đầu ra

asdanfnfnfnfnf222ads-1010 
asdanfnfnfnfnf222ads-1210 
asdanfnfnfnfnf222ads-1011 
asdanfnfnfnfnf222ads-1211 
asdadasBBBsfasdasdas-0112 
Các vấn đề liên quan