【问题标题】:How to sort array values nested inside a hash with different keys?如何对嵌套在具有不同键的哈希中的数组值进行排序?
【发布时间】:2019-06-12 08:22:50
【问题描述】:

我有一个 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;
  }
}

【问题讨论】:

    标签: arrays perl sorting hash


    【解决方案1】:

    我认为在这种情况下,您会因为数据结构过于复杂而让自己感到困难。我不知道你的数据是从哪里来的,但是如果你能得到一个这样的哈希数组会容易得多:

    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 这样的模板系统。

    【讨论】:

    • 简单而漂亮的解释!..我喜欢它
    • 谢谢!太棒了。我认为我的数据格式错误。正在使用带有数组的哈希而不是哈希数组。
    【解决方案2】:

    不要将时间戳存储为字符串,而是存储为 seconds-since-epoch。然后你可以使用普通的数字比较

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

    编辑: 任何语言/程序中时间戳处理的 SOP,除非您有一些真正超乎寻常的要求:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多