【问题标题】:Read Hashes from Array in Perl在 Perl 中从数组中读取哈希值
【发布时间】:2016-09-01 13:03:04
【问题描述】:

我是 perl 新手(昨天晚上开始)。 我对哈希数组有疑问。

以下情况: 我有几个来自日志记录应用程序的 csv 文件。日志文件是每天创建的,而且结构非常糟糕。我想将它们组合在一起并显示一些统计数据。 读取和解析 csv 并不是真正的问题,但我想将列存储在哈希中以便于访问。 在 csv 文件中,第二列 (PhysName) 是我要在其上对数据进行分组的列。所以我想,最好只将其他列保存在哈希中,将其中几个哈希保存在一个数组中,然后将数组保存在另一个哈希中,我将 PhysName 作为键。

这根本不是什么大问题:

my %dauerauftraege;

# Glob all CSV-Files in folder
my @files = glob("*.csv");

foreach my $file(@files) {
    # read the file
    open(DATA, "<$file") or die("Could not open File");

    LINE:
    foreach my $line(<DATA>) {
        chomp($line);
        if ($line eq "") {
            next LINE;
        }

        # Split Line into Fields
        my @line_data = split(";", $line);

        my $phys_name = $line_data[1];

        # skip the header file
        if ($phys_name eq "PhysName") {
            next LINE;
        }

        my %values =(
        'date_time' => $line_data[0],
        'sender' => $line_data[2],
        'recipient' => $line_data[3],
        'format' => $line_data[4],
        'transport' => $line_data[5],
        'partnername' => $line_data[6]);

        push(\@{$dauerauftraege{"$phys_name"}}, \%values);
    }
}

当我尝试使用print(Dumper(%dauerauftraege))验证这一点时,我得到以下信息:

$VAR1 = 'YYYYYYYXXXXXXXX';
$VAR2 = [
          {
            'transport' => 'FTP',
            'format' => 'V1',
            'partnername' => 'A_TEST',
            'date_time' => '2016.07.25 11:16:52',
            'sender' => 'BBB',
            'recipient' => 'CCC'
          },
          {
            'recipient' => 'CCC',
            'sender' => 'BBB',
            'partnername' => 'A_TEST',
            'date_time' => '2016.07.25 11:17:15',
            'format' => 'V1',
            'transport' => 'FTP'
          }
        ];
$VAR3 = 'XXXXXXXYYYYYYYY';
$VAR4 = [
          {
            'format' => 'V2',
            'partnername' => 'S_TEST',
            'date_time' => '2016.07.25 10:15:02',
            'recipient' => 'DDD',
            'sender' => 'AAA',
            'transport' => 'HTTP'
          },
          {
            'transport' => 'HTTP',
            'recipient' => 'DDD',
            'sender' => 'AAA',
            'partnername' => 'S_TEST',
            'format' => 'V2',
            'date_time' => '2016.07.25 10:15:30'
          }
        ];

我的第一个想法是,Dumper 将奇数 $VAR 显示为键,将偶数 $VAR 显示为值,但在我仔细查看偶数 $VAR 内的哈希后,我很确定我有将内部散列(包含列和值)插入到数组中时出错,存储在 %dauerauftraege 散列中。

所以,现在当涉及到从哈希中读取时,这里包含一个带有此代码的哈希数组

# Get the keys to iterate over them
my @dauerauftraege_keys = keys(%dauerauftraege);
print("count dauerauftraege: ".(scalar @dauerauftraege_keys)."\n");
# iterate over the keys to get the array of hashes
foreach my $dauerauftrag_key (@dauerauftraege_keys) {
    # retrive the array
    my @dauerauftrag = $dauerauftraege{"$dauerauftrag_key"};
    print("count hashes inside the array: ".(scalar @dauerauftrag)."\n");
    # iterate over the hashes and print the values
    foreach my $dauerauftrag_values (@dauerauftrag) {
        print(%{$dauerauftra_values}{'date_time'});
        print("\n");
        print(%{$dauerauftra_values}{'sender'});
        print("\n");
        print(%{$dauerauftra_values}{'recipient'});
        print("\n");
        print(%{$dauerauftra_values}{'format'});
        print("\n");
        print(%{$dauerauftra_values}{'transport'});
        print("\n");
        print(%{$dauerauftra_values}{'partnername'});
        print("\n");
    }
}

我总是收到这个错误:

count dauerauftraege: 2
count hashes inside the array: 1
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 56, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 57, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 58, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 59, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 60, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 61, <DATA> line 5.
date_timesenderrecipientformattransportpartnernamecount hashes inside the array: 1
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 56, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 57, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 58, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 59, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 60, <DATA> line 5.
Use of uninitialized value in print at ./LastRun_Evaluation.pl line 61, <DATA> line 5.
date_timesenderrecipientformattransportpartnername

这让我相信,我的问题出在下面一行:

push(\@{$dauerauftraege{"$phys_name"}}, \%values);

当我仔细阅读这一行时,我理解了以下内容: $dauerauftraege{"$phys_name"} 向我返回一个包含对数组的引用的 skalar ($),该数组被 @{} 取消引用到数组。 现在使用\%values,我将values Hash 的引用传递给push Funktion,后者将其添加到数组的引用中,由@ 前面的\ 表示。

如果有人能帮助我解决这个问题,我会非常高兴。 非常感谢你们:-)

【问题讨论】:

  • gist.github.com/anonymous/8750158b1d3a7f5d840b35c24bd4c16a 抱歉,这个小盒子的输出太长了 :) 但在我看来是一样的,我已经在我的问题中发布了上述内容。
  • foreach my $dauerauftrag_values (@dauerauftrag)print(%{$dauerauftra_values}{'date_time'}); 变量名不相同!!! $dauerauftrag_values不是$dauerauftra_values
  • 始终使用 use strict;use warnings !它们有助于避免烦人的拼写错误
  • 我喜欢一切都是英文的,除了 Daueraufträge。这些在英语中称为常规命令。变量和函数命名的一致性很重要。很高兴你所有的变量都是蛇形的,这就是 Perl 人通常这样做的方式。但是您也应该与从中获取 var 名称的语言保持一致。这使得它更容易阅读。德语没有错,但不要混用。你甚至有一半德语一半英语。德语单词中有错字。你等待修复它的时间越长,它就会得到。听起来很奇怪,不是吗? ;-)
  • @simbabque:是的,我知道,这很奇怪,用英文代码,只有一个德语单词。希望我的英语还不错;-)

标签: arrays perl csv hash


【解决方案1】:

我认为问题在于您如何访问数据结构。试试这个:

my @dauerauftraege_keys = keys %dauerauftraege;
print("count dauerauftraege: ".(scalar @dauerauftraege_keys)."\n");
# iterate over the keys to get the array of hashes
foreach my $dauerauftrag_key (@dauerauftraege_keys) {
    # retrieve the array
    my $dauerauftrag = $dauerauftraege{"$dauerauftrag_key"}; # ref to array
    my @a = @$dauerauftrag;
    print("count hashes inside the array: ".(scalar @a)."\n");
    # iterate over the hashes and print the values
    foreach my $dauerauftrag_values (@a) { # also a reference
        print $dauerauftrag_values->{'date_time'} . "\n";
        print $dauerauftrag_values->{'sender'} . "\n";
        print $dauerauftrag_values->{'recipient'} . "\n";
        print $dauerauftrag_values->{'format'} . "\n";
        print $dauerauftrag_values->{'transport'} . "\n"; 
        print $dauerauftrag_values->{'partnername'} . "\n";
    }
}

【讨论】:

  • 这真的对我有用,就像一个魅力。感谢您的代码,我现在明白了,我在哪里犯了错误。保护你! :-)
【解决方案2】:

您似乎不太了解如何取消引用数据结构。看看下面的代码,我做了一些改动,希望能让事情变得更清楚:

my @keys = keys(%dauerauftraege);

for my $key (@keys) {

    print "*** $key ***\n";

    my $aref = $dauerauftraege{$key};

    for my $values_href (@$aref){
        print "$values_href->{date_time}\n";
        print "$values_href->{sender}\n";
        print "$values_href->{recipient}\n";
        print "$values_href->{format}\n";
        print "$values_href->{transport}\n";
        print "$values_href->{partnername}\n";
    }
    print "\n";
}

perldsc

【讨论】:

  • 是的,你是对的。我在取消引用时遇到了一些问题。
【解决方案3】:

始终使用编译指示 use strict;use warnings;。它们有助于避免拼写错误和其他问题。

%dauerauftraege 是一个散列,您尝试像访问数组一样访问它。而且您正试图通过散列进行循环,同时在整个散列的每次迭代上打印。

我认为代码可能如下所示:

use strict;
use warnings;
my %dauerauftraege;

# Glob all CSV-Files in folder
my @files = glob("*.csv");

foreach my $file(@files) {
    # read the file
    open(my $fh, "<", $file) or die("Could not open File");

    LINE:
    foreach my $line(<$fh>) {
        chomp($line);
        next LINE unless($line);

        # Split Line into Fields
        my @line_data = split(";", $line);

        my $phys_name = $line_data[1];

        # skip the header file
        next LINE if ($phys_name eq "PhysName");

        @{$dauerauftraege{"$phys_name"}}
          {'date_time', 'sender', 'recipient',
           'format', 'transport', 'partnername'}=@line_data[0,2..6];
    }
}

然后打印...

# Get the keys to iterate over them
my @dauerauftraege_keys = keys(%dauerauftraege);
print("count dauerauftraege: ".(scalar @dauerauftraege_keys)."\n");
# iterate over the keys to get the array of hashes
foreach my $dauerauftrag_key (@dauerauftraege_keys) {
    print "\n$dauerauftrag_key:\n";
    print join("\n",
          @{$dauerauftraege{"$dauerauftrag_key"}}{'date_time','sender','recipient',
                          'format','transport','partnername'})."\n";
}

【讨论】:

  • 请提供词法文件句柄。
  • 非常感谢您的回答。 +1 因为我喜欢你如何用 Perl 完成“单行如果”。非常喜欢这样,让代码看起来很神:-) +1 也为use strict;use warnings; 的提示! :)
猜你喜欢
  • 2016-07-22
  • 2010-09-08
  • 2012-12-07
  • 2016-05-25
  • 2012-10-07
  • 2016-02-21
  • 2012-12-11
  • 2013-06-24
  • 1970-01-01
相关资源
最近更新 更多