Arrays 如何在Perl中整合哈希?

Arrays 如何在Perl中整合哈希?,arrays,perl,hash,reference,Arrays,Perl,Hash,Reference,我有一个哈希引用数组。散列包含2个键,用户和页面。这里的目标是遍历散列引用数组,并保持用户在打印机上打印的页面总数(这来自事件日志)。我从Excel电子表格中提取数据,并使用正则表达式提取用户名和页面。电子表格中有182行,每行包含用户名和他们在该作业上打印的页数。目前,脚本可以使用用户名和打印的页面打印每个打印作业(全部182个),但我想将其合并,以便显示:用户名266(即仅显示用户名一次,以及整个电子表格中打印的总页数) 下面是我尝试遍历哈希引用数组的过程,查看用户是否已经存在,如果已经存在

我有一个哈希引用数组。散列包含2个键,用户和页面。这里的目标是遍历散列引用数组,并保持用户在打印机上打印的页面总数(这来自事件日志)。我从Excel电子表格中提取数据,并使用正则表达式提取用户名和页面。电子表格中有182行,每行包含用户名和他们在该作业上打印的页数。目前,脚本可以使用用户名和打印的页面打印每个打印作业(全部182个),但我想将其合并,以便显示:用户名266(即仅显示用户名一次,以及整个电子表格中打印的总页数)

下面是我尝试遍历哈希引用数组的过程,查看用户是否已经存在,如果已经存在,则+=将该用户的页数添加到一个新的哈希引用数组(较小的数组)中。如果不存在,则将该用户添加到新的哈希引用数组中:

my $criteria = "USER";
my @sorted_users = sort { $a->{$criteria} cmp $b->{$criteria} } @user_array_of_hash_refs;

my @hash_ref_arr;
my $hash_ref = \@hash_ref_arr;

foreach my $index (@sorted_users)
{
    my %hash = (USER=>"",PAGES=>"");
    if(exists $index{$index->{USER}})
    {
        $hash{PAGES}+=$index->{PAGES};
    }
    else
    {
        $hash{USER}=$index->{USER};
        $hash{PAGES}=$index->{PAGES};
    }
    push(@hash_ref_arr,{%hash});
}
但这给了我一个错误:

全局符号“%index”要求在以下位置显示包名


也许我的逻辑在这方面不是最好的。我应该改用数组吗?鉴于我的数据的性质,似乎哈希是这里最好的东西。我只是不知道如何将哈希引用数组缩小到只获取用户名和它们打印的总页面(我知道我似乎多余,但我只是想弄清楚)。谢谢。

错误来自此行:

if(exists $index{$index->{USER}})
Perl 5中名后带有
{}
$
符号表示从哈希中获取标量值。名
%index
没有声明哈希。我认为您可能只需要添加一个
->
运算符,这样问题行就变成:

if(exists $index->{$index->{USER}})
但是没有数据让我不确定

另外,使用
use strict
对您也有好处,否则您将以静默方式实例化
%索引
散列,并想知道为什么您的结果没有任何意义

my %total;
for my $name_pages_pair (@sorted_users) {
  $total{$name_pages_pair->{USER}} += $name_pages_pair->{PAGES};
}

for my $username (sort keys %total) {
  printf "%20s %6u\n", $username, $total{$username};
}
然后,为了获得数据:

print "$_ : $totals{$_}\n" for keys %totals;
您也可以按用法进行排序:

print "$_ : $totals{$_}\n" for sort { $totals{$a} <=> $totals{$b} } keys %totals;
为排序{$totals{$a}$totals{$b}}键%totals打印“$\$totals{$\}\n”;

如mkb所述,错误在以下行中:

if(exists $index{$index->{USER}})
但是,在阅读代码后,您的逻辑是错误的。简单地纠正语法错误不会提供您想要的结果

我建议不要在循环中使用临时哈希,直接使用结果哈希即可

例如:

#!/usr/bin/perl
use strict;
use warnings;

my @test_data = (
    { USER => "tom", PAGES => "5" },
    { USER => "mary", PAGES => "2" },
    { USER => "jane", PAGES => "3" },
    { USER => "tom", PAGES => "3" }
);

my $criteria = "USER";
my @sorted_users = sort { $a->{$criteria} cmp $b->{$criteria} } @test_data;

my %totals;

for my $index (@sorted_users) {
    if (not exists $totals{$index->{USER}}) {
        # initialize total for this user
        $totals{$index->{USER}} = 0;
    }

    # add to user's running total
    $totals{$index->{USER}} += $index->{PAGES}
}

print "$_: $totals{$_}\n" for keys %totals;
这将产生以下输出:

$ ./test.pl
jane: 3
tom: 8
mary: 2

我得到了一大堆错误行:使用未初始化的加法值(+)在win32excel.pl第85行。但它只打印了每个用户名一次,但总共打印了0页。我使用了您的打印循环,所以我希望我能为您的回答给你们两个评分。非常感谢!您的添加确实修复了我的错误,但输出并不像预期的那样。它显示了所有打印作业(即每次用户出现在文件及其相关页面中时)。所以我的逻辑有点问题。很好。正是我所需要的。非常感谢大家。所有人都非常有用。我真的很感激。你不需要循环中的
if
语句。如果没有条目,Perl将自动创建一个条目。另外,如果print语句是:
print Dumper\%totals,它看起来会更好;
我不明白你为什么要对输入进行排序。我的意思是,当然,你是从原始问题中复制的,但在那里似乎也没有意义:-)感谢您的输入。我不知道传递散列引用会改变转储程序的输出。关于
排序
,我只是使用问题中的代码作为我的出发点。编辑代码以使用daveorg的print语句(我非常喜欢它的简洁性).我保留if语句主要是为了说明所涉及的逻辑(作为与问题代码中尝试的内容的比较)。
$ ./test.pl
jane: 3
tom: 8
mary: 2