Как я могу отсортировать этот хэш-массив? - PullRequest
0 голосов
/ 27 июня 2018

Я бы хотел отсортировать в алфавитном порядке содержимое %hash{'name'}, сохраняя соотношение других элементов @{$hash{$keys}}.

Как я могу это сделать?

my %hash = (
    date => [
        qw(
            2018/01/12
            2018/03/01
            2018/03/20
            2018/04/04
        )
    ],
    time => [
        qw(
            03:00:02
            01:00:01
            00:24:39
            11:33:33            
        )
    ],
    name => [
        qw(
            jerry
            tom
            micky
            agata            
        )
    ]
);

Желаемый вывод:

date;time;name
2018/04/04;11:33:33;agata
2018/01/12;03:00:02;jerry
2018/03/20;00:24:39;micky
2018/03/01;01:00:01;tom

Я еще ничего не пробовал, потому что не знаю с чего начать.

1 Ответ

0 голосов
/ 27 июня 2018

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

Это основная часть вашей проблемы. Ваше мышление правильное, но вы реализовали его неправильно. Вот что сейчас поставило вас в этот угол.

Давайте сначала посмотрим на ваши данные. Вы сказали, что это файл журнала, поэтому он основан на строках. Я создал этот формат.

On 2018/01/12 at 03:00:02 user jerry did stuff.
On 2018/03/01 at 01:00:01 user tom did stuff.
On 2018/03/20 at 00:24:39 user micky did stuff.
On 2018/04/04 at 11:33:33 user agata did stuff.

И ожидаемый результат - файл CSV. Опять же, это на основе строки.

date;time;name
2018/04/04;11:33:33;agata
2018/01/12;03:00:02;jerry
2018/03/20;00:24:39;micky
2018/03/01;01:00:01;tom

Таким образом, понятно, что структура, в которой вы хотите, чтобы данные находились, все еще основана на строках.

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

screenshot of libreoffice spreadsheet with the example data

Каждый из столбцов является одним значением строки. Итак, давайте сделаем это.

my @events; # or something like that
while (my $row = <$log_fh>) {
    my ( $date, $time, $name ) = parse_row($row); # we don't care about this implementation

    push @events, {
        date => $date,
        time => $time,
        name => $name,
    };
}

Теперь у нас есть эта структура данных (которую я вывел с помощью Data :: Printer ).

[
    [0] {
        date   "2018/01/12",
        name   "jerry",
        time   "03:00:02"
    },
    [1] {
        date   "2018/03/01",
        name   "tom",
        time   "01:00:01"
    },
    [2] {
        date   "2018/03/20",
        name   "micky",
        time   "00:24:39"
    },
    [3] {
        date   "2018/04/04",
        name   "agata",
        time   "11:33:33"
    }
]

Как видите, в каждой строке есть одна ссылка на хеш, которая содержит ключ для даты, один для времени и один для имени.

Теперь мы можем отсортировать любые ключи внутри этих структур. Это просто .

my @events_by_name = sort { $a->{name} cmp $b->{name} } @events;
my @events_by_date = sort { $a->{date} cmp $b->{date} } @events;
my @events_by_time = sort { $a->{time} cmp $b->{time} } @events;

И затем вы можете создавать CSV-файлы для каждого из них.

open my $fh, '>', 'events_by_name.csv' or die $!;
foreach my $event (@events_by_name) {
    print $fh join ';', $event->{name}, $event->{date}, $event->{time};
    print $fh "\n";
}
close $fh;

Или вы можете выполнить итерацию по количеству событий, открыть несколько одновременно и выполнить цикл только один раз.

open my $fh_name, '>', 'events_by_name.csv' or die $!;
open my $fh_date, '>', 'events_by_date.csv' or die $!;
for (my $i = 0; $i < @events_by_name; $i++) {
    print $fh_name join(
         ';', 
         @events_by_name->[$i]->{name}, 
         @events_by_name->[$i]->{date}, 
         @events_by_name->[$i]->{time},
    ); 
    print $fh_name "\n";

    print $fh_date join(
         ';', 
         @events_by_name->[$i]->{name}, 
         @events_by_name->[$i]->{date}, 
         @events_by_name->[$i]->{time},
    ); 
    print $fh_date "\n";
}
close $fh_name;
close $fh_date;

Вы можете дополнительно сократить это, используя другой цикл.

open my $fh_name, '>', 'events_by_name.csv' or die $!;
open my $fh_date, '>', 'events_by_date.csv' or die $!;
for (my $i = 0; $i < @events_by_name; $i++) {
    foreach my $fh ($fh_name, $fh_date) {
        print $fh join(
             ';', 
             @events_by_name->[$i]->{name}, 
             @events_by_name->[$i]->{date}, 
             @events_by_name->[$i]->{time},
        ); 
        print $fh "\n";
    }
}
close $fh_name;
close $fh_date;

Как видите, гораздо важнее сохранять структуру на основе линий, когда вы имеете дело со строками.

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