如何对嵌套在具有不同键的哈希中的数组值进行排序?

时间:2019-01-18 04:20:13

标签: arrays perl sorting hash

我有一个html表,其中显示了不同类型的中断的中断开始时间和结束时间。目前,我正在按中断类型对中断进行排序,但我希望能够按最早的开始时间对其进行排序。每个开始和结束的时间都已经按顺序排列了,但是无论类型如何,我都在设法使它们按顺序排列。我知道要按值排序,通常会使用某种值比较,例如“ sort {$ h {$ a} <=> $ h {$ b}} keys(%h);”

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 个答案:

答案 0 :(得分:3)

我认为在这种情况下,您的生活变得很艰难,因为您的数据结构不必要地复杂。我不知道您的数据来自哪里,但是如果您能获得如下所示的哈希数组,则将容易得多:

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',
});

然后对这些代码进行排序和打印的代码变得微不足道了。

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;
}

值得注意的是,这仅适用于您,因为您的时间戳可以被视为易于排序的字符串。如果时间戳更加复杂且包含日期,那么您可能希望使用Time::PieceDateTime之类的东西将它们转换为可排序的数据。

我还要提到,有一天您会发现,在Perl代码中包含原始HTML标签是灾难的根源。使用像Template Toolkit这样的模板系统会更好。

答案 1 :(得分:1)

不要将时间戳记存储为字符串,而是将其存储为秒数。然后您可以使用普通的数值比较

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

编辑:用于任何语言/程序的时间戳处理的SOP,除非您确实有一些与众不同的要求:

  1. 解析输入格式以将时间戳转换为“ X epoch”
    • 始终转换为UTC,即确定是否未指定时区
    • 确定输入提供的分辨率(秒,毫秒,微秒)
    • Date::Manip在这里可以成为您的朋友
  2. 将算法中的时间戳记作为数值处理
    • 比较:a < b-> a在b之前发生
    • 差异:a - b以您指定的分辨率
  3. 将时间戳转换为所需的输出格式
    • 如果您可以控制输出格式,请始终选择精确的格式,例如直接使用UTC时间戳或ISO-8601格式
    • 再次Date::Manip::Date printf() method可以在这里成为您的朋友