Perl:在复杂哈希中生成数组

Zai*_*aid 1 perl perl-data-structures

为了使我的数据更易于访问,我想将表格数据存储在复杂的哈希中.当脚本循环遍历我的数据时,我正在尝试增加'HoHoHoA'.根据'perldsc'中的指南:

push @ { $hash{$column[$i]}{$date}{$hour} }, $data[$i];
Run Code Online (Sandbox Code Playgroud)

该脚本编译并运行没有问题,但不会向哈希添加任何数据:

print $hash{"Frequency Min"}{"09/07/08"}{"15"}; 
Run Code Online (Sandbox Code Playgroud)

即使密钥应该存在,也不返回任何内容.在哈希上运行'exists'表示它不存在.

我正在阅读的数据文件如下所示:

DATE       TIME     COLUMN1 COLUMN2 COLUMN3...    
09/06/2008 06:12:56 56.23   54.23   56.35...
09/06/2008 06:42:56 56.73   55.28   54.52...
09/06/2008 07:12:56 57.31   56.79   56.41...
09/06/2008 07:42:56 58.24   57.30   58.86...
.
.
.
Run Code Online (Sandbox Code Playgroud)

我希望将任何给定日期和小时的数组中每列的值组合在一起,因此{COLUMN},{DATE}和{HOUR}的三个哈希值.

结果结构如下所示:

%monthData = (
               "COLUMN1" => {
                                    "09/06/2008" => {
                                                      "06" => [56.23,56.73...],
                                                      "07" => [57.31,58.24...]
                                                    }
                            },
               "COLUMN2" => {
                                    "09/06/2008" => {
                                                      "06" => [54.23,55.28...],
                                                      "07" => [56.79,57.30...]
                                                    }
                            },
               "COLUMN3" => {
                                    "09/06/2008" => {
                                                      "06" => [56.35,54.52...],
                                                      "07" => [56.41,58.86...]
                                                    }
                            }
             );
Run Code Online (Sandbox Code Playgroud)

看看我的代码:

use feature 'switch';
open DATAFILE, "<", $fileName or die "Unable to open $fileName !\n";

    my %monthData;

    while ( my $line = <DATAFILE> ) {

        chomp $line;

        SCANROWS: given ($row) {

            when (0) { # PROCESS HEADERS

                @headers = split /\t\t|\t/, $line;
            }

            default {

                @current = split /\t\t|\t/, $line;
                my $date =  $current[0];
                my ($hour,$min,$sec) = split /:/, $current[1];

                # TIMESTAMP FORMAT: dd/mm/yyyy\t\thh:mm:ss

                SCANLINE: for my $i (2 .. $#headers) {

                    push @{ $monthData{$headers[$i]}{$date}{$hour} }, $current[$i];

                }
            }
        }
    }

    close DATAFILE;

    foreach (@{ $monthData{"Active Power N Avg"}{"09/07/08"}{"06"} }) {
        $sum += $_;
        $count++;
    }

    $avg = $sum/$count; # $sum and $count are not initialized to begin with.
    print $avg; # hence $avg is also not defined.
Run Code Online (Sandbox Code Playgroud)

希望我的需要足够清楚.如何将值附加到这些子哈希中的数组?

Cha*_*ens 8

这应该为你做.

#!/usr/bin/perl

use strict;
use warnings;

use List::Util qw/sum/;
sub avg { sum(@_) / @_ }

my $fileName = shift;

open my $fh, "<", $fileName
    or die "Unable to open $fileName: $!\n";

my %monthData;

chomp(my @headers = split /\t+/, <$fh>);

while (<$fh>) {
    chomp;
    my %rec;
    @rec{@headers} = split /\t+/;
    my ($hour) = split /:/, $rec{TIME}, 2;

    for my $key (grep { not /^(DATE|TIME)$/ } keys %rec) {
        push @{ $monthData{$key}{$rec{DATE}}{$hour} }, $rec{$key};
    }
}

for my $column (keys %monthData) {
    for my $date (keys %{ $monthData{$column} }) {
        for my $hour (keys %{ $monthData{$column}{$date} }) {
            my $avg = avg @{ $monthData{$column}{$date}{$hour} };
            print "average of $column for $date $hour is $avg\n";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

需要注意的事项:

  • 严格警告 pragmas
  • List :: Util模块获取sum函数
  • 将数组放在标量上下文中以获取数组中的项数(在avg函数中)
  • 更开放的三个参数版本
  • 词法文件句柄(而不是旧的裸字样式文件句柄)
  • 首先在循环外读取标题,以避免在其中包含特殊逻辑
  • 使用哈希切片将文件数据转换为结构化记录
  • 避免将时间分成超过必要的第三个参数进行拆分
  • 通过仅指定我们想要在列表赋值中捕获的变量来避免无用变量
  • 使用grep来防止DATE和TIME键被放入%monthData
  • 嵌套的for循环,每个循环处理散列中的一个级别