Сортировка массива даты и времени в Perl - PullRequest
0 голосов
/ 01 мая 2018

Я пытался отсортировать даты в Perl. Строка datetime находится в хэше массивов. После долгих поисков я использовал функцию сортировки Perl. К моему удивлению это сработало. Мой код и ввод ниже:

use strict;
use warnings;

my %hashofarrays;

$hashofarrays{'joe tribiani'} = ['16/3/28 13:42','XII','99.93%'];
$hashofarrays{'Ross'} = ['16/3/28 13:43','XII','76.93%'];
$hashofarrays{'sue grace'} = ['11/7/5 12:07','VI','77.58%'];

foreach my $key (   sort{$hashofarrays{$a}[0] cmp $hashofarrays{$b}[0]}      keys %hashofarrays ) {
print "$key =>", join (", ", @{$hashofarrays{$key}}), "\n";
}

Я правильно это делаю? Если я, как это работает?

Если это неправильно, то что мне нужно сделать, чтобы отсортировать строку даты и времени?

В результате должны быть перечислены записи, отсортированные в порядке возрастания по дате и времени.

Формат даты и времени: «ГГ / ММ / ДД» или «ГГ / М / Д»

Мои данные:

joe tribiani, 16/3/28 13:42,XII,99.93%
Ross,16/3/28 13:43,XII,95.93%
sue grace,11/7/5 12:07,VI,77.58%

Мой исключенный вывод:

sue grace =>11/7/5 12:07, VI, 77.58%
joe tribiani =>16/3/28 13:42, XII, 99.93%
Ross =>16/3/28 13:43, XII, 76.93%

1 Ответ

0 голосов
/ 01 мая 2018

Что делает ваш код

foreach my $key ( 
    sort { $hashofarrays{$a}[0] cmp $hashofarrays{$b}[0] }
    keys %hashofarrays 
) {
    print "$key =>", join (", ", @{$hashofarrays{$key}}), "\n";
}

При этом используются ключи хэша для сортировки элементов хэша по первому элементу ссылки на массив, который находится внутри этого ключа в хэше. Он использует cmp, что является ascii-betical сортировкой, а не числовой. Это означает, что 10 предшествует 2, потому что 1 является символом ниже, чем 2.

Для сортировки по дате это имеет смысл. Но поскольку ваш формат даты не соответствует двум цифрам для месяцев и дней, он не будет сортироваться должным образом.

18/5/1    # sorted last
18/10/1   # sorted first

Для этих двух дат первая из дат октября будет отсортирована первой, что неверно.

Что нужно сделать вместо этого

Если вы не можете очистить входные данные, вам нужно обработать их, чтобы выяснить значение за датой, а не полагаться на представление для сортировки. Синтаксический анализ дат - это его собственная проблема, и мы будем использовать Time :: Piece , чтобы сделать это, что уже некоторое время было в ядре Perl.

Мы могли бы сделать это так: псевдокод:

sort { parse($a) <=> parse($b) } ...

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

Есть способ сделать это более эффективным, но это немного сложнее.

use strict;
use warnings;
use Time::Piece;

my %values = ( 'joe tribiani' => [ '16/3/28 13:42', 'XII', '99.93%' ],
               'Ross'         => [ '16/3/28 13:43', 'XII', '76.93%' ],
               'sue grace'    => [ '11/7/5 12:07',  'VI',  '77.58%' ], );

my @sorted_keys = map { $_->[1] }
    sort { $a->[0] <=> $b->[0] }
    map {
        [ Time::Piece->strptime( $values{$_}->[0], '%y/%m/%d %H:%M' )->epoch, $_ ]
    }
    keys %values;

use Data::Dumper;
print Dumper @sorted_keys;

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

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

Обратите внимание, что нам нужно использовать оператор числового сравнения <=> сейчас, потому что мы сортируем значения epoch , которые являются просто числами (много секунд из 1970-01-01T00:00:00).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...