How to sort array values nested inside a hash with different keys?

Обновить

April 2019

Просмотры

49 раз

1

У меня есть HTML-таблица, показывающая начало ППР и конечное время с различными типами отключений. В настоящее время я сортировка простоев в порядке типа ППРА, но я хотел бы иметь возможность сортировать их ранними до последних времен начала. Времена в каждом начало и конец уже будет в порядке, но я стараюсь, чтобы получить их в порядке, независимо от типа. Я знаю, что для сортировки по значению, обычно используется какой-то ценности сравнить, как это «рода {$ ч {$ а} <=> $ ч {$ B}} ключей (% Н);»

Currently they sort like:
1 | phone | 00:00:00 | 04:08:03
2 | phone | 14:26:03 | 18:00:00
3 | television | 12:34:19 | 12:34:25

But it should be like:
1 | phone | 00:00:00 | 04:08:03
2 | television | 12:34:19 | 12:34:25
3 | phone | 14:26:03 | 18:00:00

Это мой код.

my %outages;

my @outage_times = qw(start end);

my %outage_reasons = (
  'tv' => 'television',
  'p' => 'phone'
);

foreach my $outage_reason (values %outage_reasons) {
  foreach my $outage (@outage_times) {
    $outages{$outage_reason}{$outage} = [];
  }
}

$outages{television}{start} = ['00:00:00', '14:26:03'];
$outages{television}{end} = ['04:08:03', '18:00:00'];
$outages{phone}{start} = ['12:32:02'];
$outages{phone}{end} = ['12:38:09'];

my $outage_number = 1;

foreach my $outage (sort keys %outages){
  for my $i (0 .. scalar (@{$outages{$outage}{start}})-1) {
    my $outage_start_time = $outages{$outage}{start}[$i];
    my $outage_end_time = $outages{$outage}{end}[$i];
    my $row_html = "<tr><td>$outage_number</td><td>$outage</td>";
        $row_html .= "<td>$outage_start_time</td>";
        $row_html .= "<td>$outage_end_time</td></tr>";
    $outage_number += 1;
  }
}

2 ответы

1

Don't store the time stamp as strings but as seconds-since-epoch. Then you can use normal numeric compare

foreach my $outage (sort { $a->{start} <=> $b->{start} values %outages) {

EDIT: SOP for time stamp processing in any language/program, unless you have some really out-of-this-world requirements:

  1. parse the input format to convert time stamps to "X since epoch"
    • always convert to UTC, ie. determine time zone if it is not given
    • determine resolution (seconds, milliseconds, microseconds) provided by input
    • Date::Manip can be your friend here
  2. process time stamps in your algorithm as numerical values
    • compare: a < b -> a happens before b
    • differences: a - b at your given resolution
  3. convert timestamps to desired output format
    • if you have control of the output format, always opt for a precise format, e.g. use the UTC timestamp directly or ISO-8601 format
    • again Date::Manip::Date printf() method can be your friend here
3

I think this is a situation where you are making life difficult for yourself because your data structure is unnecessarily complicated. I don't know where your data is coming from, but it would be far easier if you could get an array of hashes like this:

my @outages = ({
  type  => 'phone',
  start => '00:00:00',
  end   => '04:04:03',
}, {
  type  => 'phone',
  start => '14:26:03',
  end   => '18:00;00',
}, {
  type  => 'television',
  start => '12:34:19',
  end   => '12:34:25',
});

The code to sort and print these then becomes almost trivial.

my $number = 1;
for (sort { $a->{start} cmp $b->{start} } @outages) {
  my $row_html = '<tr>'
               . "<td>$number</td>"
               . "<td>$_->{type}</td>"
               . "<td>$_->{start}</td>"
               . "<td>$_->{end}</td>"
               . "</tr>\n";
  $number++;
  print $row_html;
}

It's worth noting that this only works because your timestamps can be treated as strings which are easily sorted. If the timestamps were more complicated and included dates then you're probably going to want to convert them to sortable data using something like Time::Piece or DateTime.

I'd also mention that one day you'll discover that including raw HTML tags in your Perl code is a recipe for disaster. Far better to use a templating system like the Template Toolkit.