Как сортировать метки времени в формате dd: mm: yyyy hh24: mi: ss в порядке убывания в Perl? - PullRequest
5 голосов
/ 10 октября 2011

Я должен отсортировать мои хеш-ключи, которые представляют собой временную метку (dd:mm:yyyy hh24:mi:ss) в порядке убывания.

sort { $b <=> $a } keys %time_spercent

этот путь не дает мне того, что я намерен делать.Скорее это заканчивается сортировкой с более высокими часами и минутами сначала, даже если дата не такова.Например, так я получаю, когда делаю сортировку, как я уже упоминал.

21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

Скорее, я хочу, чтобы они были расположены в этом порядке как по дате, так и по времени.

05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:48:37
21:01:2011 16:51:09
21:01:2011 16:49:54

Любые указатели на то, как это можно сделать, будут с благодарностью приняты.

Обновление

foreach my $status_date( 
     map  { $_->[0] }
     sort { $b->[1] cmp $a->[1] }
     map  { [$_, sorting_desc($_)] } keys % {$com_sam->{ $s1 } } ) 

и

sub sorting_desc {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/) {
        return "$2:$1:$3:$4:$5:$6";
    }
}

- подпрограмма для сортировки.

Я также пытался

foreach my $status_date( 
    map  { $_->[0] }
    sort { $b->[1] cmp $a->[1] }
    map { [$_, (split/[:\s][1]] } keys % {$com_sam->{ $s1 } } )

, но не ожидал результатов.

Все, что я получаю, это:

WGA_PD7124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19
3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30

Ответы [ 5 ]

11 голосов
/ 10 октября 2011

Можете ли вы изменить свой формат на yyyy:mm:dd hh24:mi:ss?В этот момент у вас будет натуральный порядок.По сути, гораздо удобнее для машин иметь все в порядке убывания важности:)

РЕДАКТИРОВАТЬ: Затем просто упорядочить, используя сравнения string , так как это, естественно, отсортирует правильный путь.*

3 голосов
/ 10 октября 2011

Из твоего вопроса мне неясно, как ты на самом деле хочешь разобраться и как ты привел примеры.Я не могу обнаружить какой-либо порядок в примере вашего ожидаемого порядка сортировки.Вероятное решение находится внизу.

Позвольте мне уточнить:

Учитывая текстовый файл "ts" со следующим содержанием (ваш пример):

> cat ts
21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

СтандартСортировка приводит к следующему выводу:

> perl -e '@a = <>; print sort @a' ts
05:04:2011 11:48:37
05:04:2011 11:48:37
05:04:2011 11:51:13
05:04:2011 11:51:13
21:01:2011 16:49:54
21:01:2011 16:51:09
26:01:2011 11:01:40
26:01:2011 11:02:55

В то время как предложенная вами сортировка по убыванию чисел производит следующий порядок:

> perl -e '@a = <>; print sort { $b <=> $a } @a' ts
26:01:2011 11:02:55
26:01:2011 11:01:40
21:01:2011 16:51:09
21:01:2011 16:49:54
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

Чтобы уточнить числовую сортировку: оператор космического корабля <=> обеспечиваетчисленная интерпретация двух его операндов.Таким образом, строки $ a и $ b, каждая из которых содержит дату и время, интерпретируются так, как если бы они были числами.Для этого perl в этом примере извлекает дату и останавливается на первом «:».Вот почему время и даже месяц и год полностью игнорируются, и мы сортируем только по дню месяца в порядке убывания.

Наконец, если вы действительно хотите выполнить обратную сортировку по дате, тогда времяи нужно сохранить формат, который вы можете использовать этот код:

> perl -e '@a = <>; sub dmyt2ymdt { my $dmyt=shift; $ymdt=join(q(), (split(/[:\s]+/,$dmyt))[2,1,0,3,4,5])}   print sort { dmyt2ymdt($b) <=> dmyt2ymdt($a) } @a' ts
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37
26:01:2011 11:02:55
26:01:2011 11:01:40
21:01:2011 16:51:09
21:01:2011 16:49:54

Вот лучшая отформатированная версия (которую я не тестировал):

sub dmyt2ymdt {
  my $dmyt = shift;
  my ($day, $mon, $year, $h, $m, $s) = split(/[:\s]+/, $dmyt);
  return join('', $year, $mon, $day, $h, $m, $s);
}

Эта функция сортировки

sort { dmyt2ymdt($b) <=> dmyt2ymdt($a) }

затем довольно часто вызывает вышеуказанного помощника.В вашем примере у нас есть 8 записей в списке для сортировки, и функция вызывается 24 раза.Так что это неэффективно.Но для небольших списков до пары сотен или даже тысяч записей это может быть хорошо для вас.Если у вас большие списки, вы должны выполнить преобразование формата только один раз, но это все еще стоит памяти.Таким образом, для больших списков вам нужно соотносить память с временем выполнения, как это часто бывает.

Если производительность является критерием оптимизации, вы можете выполнить преобразование на лету, как было прокомментировано и показано в других ответах.и комментарии как это:

sort { $b <=> $a }  map { dmyt2ymdt($_) } @a

.. для моего примера выше.Теперь вы делаете преобразование только один раз для каждого элемента.Тем не менее, мы должны держать временный список в памяти.Я не совсем уверен, насколько хорошо Perl может оптимизировать вышеупомянутую конструкцию.Можно подумать, что легче оптимизировать следующее:

reverse sort map { dmyt2ymdt($_) } @a

, что также будет работать для тестового набора.По умолчанию сортировка возвращается к сравнению строк, которое совпадает с числовым сравнением строк одинаковой длины, которые не используют пробелы в тех местах, где другие строки имеют цифры.

Надеюсь, это поможет!

2 голосов
/ 10 октября 2011

Ответ Джона Скита лучше!(т. е. просто измените свою метку времени, если можете, на формат ISO 8601 .)

Но если вы не можете изменить формат, вы можете сделать что-то вроде:

#!/usr/bin/perl -w
use strict;

my %h;

while(<DATA>) {
    chomp;
    $h{$_}++;
}

sub iso_8601 {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/) {
        return "$3:$2:$1:$4:$5:$6";
    }    
}

foreach my $key (sort {iso_8601($a) cmp iso_8601($b)} keys %h) { 
    print "$key -- $h{$key}\n";
}

__DATA__
21:01:2011 16:51:09
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
05:04:2011 11:48:37

(Дублирующие метки времени, я полагаю, у тебя есть своя собственная логика, с которой нужно иметь дело. Хэшируя их, подсчитываются дубликаты, а я просто печатаю их счет ...)

Результат:

21:01:2011 16:49:54 -- 1
21:01:2011 16:51:09 -- 1
26:01:2011 11:01:40 -- 1
26:01:2011 11:02:55 -- 1
05:04:2011 11:48:37 -- 2
05:04:2011 11:51:13 -- 2

Редактировать

ОК, если вы обеспокоены эффективностью, (sort {iso_8601($a) cmp iso_8601($b)} keys %h) не является лучшим , поскольку iso_8601 () функция вызывается много раз за элемент хеша.

Для формы " Преобразование Шварца " вы можете сделать:

print join("\n",
    map { $_->[0].' -- '.$h{$_->[0]} }
    sort { $a->[1] cmp $b->[1] }
    map {[$_,iso_8601($_)]} 
        keys %h);

, которая выдаст тот же результат, что и выше.Затем вы вызываете iso_8601() только один раз для каждого хеш-ключа, а не несколько раз ...

Чтобы разобрать это (он идет справа налево, снизу вверх):

keys %h                         # list of all the keys of the hash
map {[$_,iso_8601($_)]}         # create anon array with 2 elements:
                                # original stamp and ISO 8601 stamp
sort { $a->[1] cmp $b->[1] }    # list sorted on the ISO 8601 stamp
map { $_->[0].' -- '.$h{$_->[0]} }  # a list of strings with original stamp
                                    # and hash count
join("\n",                      # join the list into a string with a "\n"

РЕДАКТИРОВАТЬ2

Мне трудно понять, что вы хотите.Попробуйте это:

#!/usr/bin/perl -w
use strict;

my %h;
my $i=0;

while(<DATA>) {
    chomp;
    $h{$_}++;
}

sub iso_8601 {
    $_ = shift;
    if (/(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)$/) {
        $i++;
        return "$3-$2-$1 $4:$5:$6";
    }    
}

foreach my $key (sort {iso_8601($b) cmp iso_8601($a)} keys %h) { 
    print iso_8601($key).":\t\t"."$key -- $h{$key}\n";
}

print "\n";

Вывод:

YYYY-MM-DD HH:MM:SS                 your record... 
2011-09-01 10:48:18:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18 -- 1
2011-09-01 10:48:18:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18 -- 1
2011-08-25 10:20:16:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16 -- 1
2011-08-25 10:20:16:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16 -- 1
2011-08-25 10:19:05:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05 -- 1
2011-08-25 10:19:05:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05 -- 1
2011-08-25 10:17:26:        MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26 -- 1
2011-08-25 10:17:26:        MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26 -- 1
2011-07-01 16:13:55:        WGA_PD7124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55 -- 1
2011-07-01 16:11:23:        WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23 -- 1
2011-07-01 11:04:26:        WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26 -- 1
2011-05-04 17:35:52:        WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52 -- 1
2011-05-04 17:35:52:        WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52 -- 1
2011-05-04 17:34:27:        WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27 -- 1
2011-05-04 17:34:27:        WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27 -- 1
2011-03-23 10:03:23:        PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23 -- 1
2011-03-23 10:02:30:        PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30 -- 1
2011-02-15 09:24:31:        3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31 -- 1
2011-02-15 09:21:19:        3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19 -- 1
2011-02-15 09:16:32:        3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32 -- 1
2011-02-09 09:54:48:        CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48 -- 1
2011-02-09 09:54:48:        3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48 -- 1
2011-02-09 09:51:02:        3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02 -- 1
2011-02-09 09:51:02:        CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02 -- 1

Это то, что вы думаете?Он анализирует отметку времени в конце строки и сортирует эти записи в порядке убывания.В чем проблема с этим?

0 голосов
/ 13 октября 2011

Во-первых, поймите, что вы пытаетесь сделать. Затем заставьте это работать. Затем при необходимости оптимизируйте.

Один из способов легко сравнить временные метки - конвертировать их в смещения эпохи. Вы можете использовать Time :: Local . Учитывая, что вы получаете не произвольные значения, а довольно четко определенные временные метки, вы можете заняться небольшой преждевременной оптимизацией и использовать версию _nocheck timelocal или timegm.

.

Вот один из способов сделать это, используя предоставленные вами образцы данных:

#!/usr/bin/env perl

use strict; use warnings;

use Time::Local 'timelocal';

my @data;

while (my $line = <DATA>) {
    last unless $line =~ /\S/;
    chomp $line;
    push @data, [ split ' ', $line ];
}

@data = sort compare_records_descending_time @data;

print join("\t", @$_), "\n" for @data;

sub compare_records_descending_time {
    return ts2time($b) <=> ts2time($a);
}

sub ts2time {
    my ($record) = @_;
    my $ts = "@{ $record }[-2, -1]";

    # timestamp is day:mon:year hr:min:sec
    # timelocal expects arguments in sec, min, hr, day, mon, year

    return timelocal(($ts =~ /([0-9]+)/g)[5, 4, 3, 0, 1, 2]);
}

__DATA__
124a WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192654  01:07:2011 16:13:55
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Unknown(Unknown)        192655  01:07:2011 16:11:23
WGA_PD7124a     WGA_PD7124a     95(2)   95(2)   95      100.00  193     Male(Unknown)   192656  01:07:2011 11:04:26
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184558  04:05:2011 17:35:52
WGA_PD6355b     WGA_PD6355b     96(1)   96(1)   96      100.00  388     Unknown(Unknown)        184557  04:05:2011 17:34:27
WGA_PD6355b     WGA_PD6355a     96(1)   66(31)  66      95.45   388     Unknown(Unknown)        184557  04:05:2011 17:34:27
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174878  15:02:2011 09:24:31
3074    3074    87(10)  87(10)  87      100.00  109     Unknown(Unknown)        174970  15:02:2011 09:21:19
3074    3074    87(10)  87(10)  87      100.00  109     Female(Unknown) 174860  15:02:2011 09:16:32
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173382  09:02:2011 09:54:48
3163    3163    90(7)   90(7)   90      100.00  176     Unknown(Unknown)        173284  09:02:2011 09:51:02
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173382  09:02:2011 09:54:48
CHP-212 CHP-212 94(3)   94(3)   94      100.00  269     Unknown(Unknown)        173284  09:02:2011 09:51:02
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2631        MGH_2631        90(8)   90(8)   90      100.00  211     Male(Unknown)   200946  25:08:2011 10:17:26
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200943  01:09:2011 10:48:18
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200944  25:08:2011 10:20:16
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Unknown(Unknown)        200945  25:08:2011 10:19:05
MGH_2101        MGH_2101        80(18)  80(18)  80      100.00  359     Male(Unknown)   200946  25:08:2011 10:17:26
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179502  23:03:2011 10:03:23
PD4294c PD4294c 95(2)   95(2)   95      100.00  221     Unknown(Unknown)        179470  23:03:2011 10:02:30
0 голосов
/ 12 октября 2011

У меня была такая же проблема некоторое время назад, и я решил преобразовать формат, когда сортировал список таким же образом, как предложил Джон Скит, это мой кусок кода:

my @source = <DATA>;
my @data =  sort {$a<=>$b} map { m!(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)!; "$3$2$1$4$5$6";} @source;
foreach ( @data ) {
    s!(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})!$3:$2:$1 $4:$5:$6!;
    print $_, "\n";
}

__DATA__
05:04:2011 11:48:37
21:01:2011 16:49:54
26:01:2011 11:02:55
26:01:2011 11:01:40
05:04:2011 11:51:13
05:04:2011 11:51:13
05:04:2011 11:48:37
21:01:2011 16:51:09
15:04:2012 11:48:37

результат:

21:01:2011 16:49:54
21:01:2011 16:51:09
26:01:2011 11:01:40
26:01:2011 11:02:55
05:04:2011 11:48:37
05:04:2011 11:48:37
05:04:2011 11:51:13
05:04:2011 11:51:13
15:04:2012 11:48:37
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...