Я пытался отсортировать даты на Perl. Строка datetime находится в хэше массивов. После долгих поисков в Google я использовал функцию сортировки 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%
Но, учитывая, что в некоторых случаях M - однозначное число, этого не произойдет :)
Верно. Я бы сказал, проанализируйте значения для сортировки. Пришло время для некоторого преобразования Шварца.
Спасибо, я добавил свои данные и ожидаемый результат
Можете ли вы также сказать нам, какой формат даты? Первое значение - год или день?
Первое значение - год. Формат даты: «ГГГГ / ММ / ДД» или «ГГГГ / М / Д».
Спасибо за редактирование.
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
Для этих двух дат более поздняя октябрьская дата будет отсортирована первой, что неверно.
Если вы не можете очистить входные данные, вам необходимо обработать их, чтобы вычислить значение за датой, вместо того, чтобы полагаться на представление для сортировки. Анализ дат - это отдельная проблема, и мы будем использовать для этого Время :: Кусок, который уже некоторое время присутствует в ядре 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;
Это называется Преобразование Шварца. По сути, он обрабатывает значения один раз, помещает их в другую ссылку на массив вместе с фактическими значениями, которые сортируются. Затем он сортирует предварительно обработанные значения и затем возвращает их.
Это намного эффективнее, и из-за синтаксического анализа он будет работать для всех дат, которые могут отображаться в ваших значениях, без их неправильной сортировки.
Обратите внимание, что сейчас нам нужно использовать оператор числового сравнения <=>
, потому что мы сортируем значения эпоха, которые являются просто числами (много секунд из 1970-01-01T00:00:00
).
Спасибо. Решение идеально подходит для моей проблемы.
Какого результата вы ожидаете? Пожалуйста, редактировать свой вопрос и сообщите нам, каков ожидаемый заказ. В настоящий момент вы выполняете сортировку в формате ascii по первому элементу ссылки на массив. Если эта дата находится в порядке
YY/M/D
, это, вероятно, сработает.