包含多个数组的Perl哈希

时间:2013-06-19 19:16:11

标签: perl

通常情况下,我可以围绕哈希和数组的所有不同复杂性进行思考,但我似乎无法使其正常工作......

这是我的阵列:

$event['date'] = $my_date;
$event['machine'] = $my_machine;

这就是我希望我的哈希看起来像

$User{$name}{'allowed'} = 52;
$User{$name}{'denied'} = 4;
$User{$name}{'events'}[] = @event;

我需要遍历每个用户(当前有效),然后在该用户循环中完成每个事件。

2个问题:

  1. 如何将多个事件数组实例添加到我的哈希?
  2. 如何遍历这些数组?
  3. 任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:3)

Perl中的数组具有以下属性:

  • 它以连续范围的正整数为索引,从0开始。
  • 它将标量作为值
  • 它们用方括号编制索引,例如: $array[0] = $val

另一方面,哈希具有属性

  • 它由唯一字符串索引。
  • 键值对无法保证订单。
  • 它将标量视为值。
  • 它们用卷曲索引,例如$hash{"some key"} = $val。如果密钥是有效标识符,则引号是可选的:$hash{some_key} = $val

散列和数组都不是标量,但您可以使用一元\运算符作为参考,然后是标量。

不要使用名称为“associative array”的其他语言混淆Perl调用哈希值,或者使用相同的哈希值和数组语法。

对于您的事件数据结构,您还需要一个哈希:

my %event = (
  date    => $my_date,
  machine => $my_machine,
);
...;
$User{$name}{events} = \%event; # see the reference operator.

如果您希望用户拥有多个事件,您希望将该条目用作数组引用,并将\%event推送到结尾:

push @{ $User{$name}{events} }, \%event;

@{ ... }接受数组引用,取消引用它到数组。

使用数据结构

给定一个哈希,你可以循环遍历

这样的键
for my $key (keys %hash) { ... }

给定hashref,我们必须首先取消引用它:

for my $key (keys %{ code_producing_hashref() }) { ... }

给定数组引用,我们必须在循环之前取消引用它:

for my $value (@{ code_producing_arrayref() }) { ... }

例如,为了循环每个事件,我们可以做

for my $user (keys %User) {
  say "User $user has the following events:";
  for my $event (@{ $User{$user}{events} }) {
    say "date=$event->{date} machine=$event->{machine}";
  }
}

$hashref->{$key}语法访问hashref中的字段。它的作用类似于my %hash = %$hashref; $hash{$key},除非没有不必要的副本。

进一步阅读

Perl引用可能令人困惑,而且语法非常丑陋。我建议您阅读文档以便更好地理解:

  1. perlreftut
  2. perlref
  3. perldsc

答案 1 :(得分:3)

我不知道我是否完全正确。

你所描述的"我的阵列"看起来更像是散列%event,因为你使用的是名字,而不是indizes。因此,让我们假设以下内容。

您有事件,每个事件都是哈希%event,定义如下:

my %event;
$event{date} = $my_date;
$event{machine} = $my_machine;

请注意,您可以省略简单哈希键上的引号。现在,如果您已定义了多个类似事件,请说出%event1%event2等等,则将它们添加到数组中。您必须添加对这些事件哈希的引用!

my @events = ( \%event1, \%event2 );

现在,您的用户哈希事件应该定义为:

$user{$name}{events} = [ @events ];

此处,您需要将用户的事件设置为对数组的引用。内容将是您的事件列表包含的内容。这基本上会将@events的元素复制到您的用户对象中。您也可以像

一样编写它
$user{$name}{events} = \@events;

但是你直接引用了@events数组。

现在循环很容易。

foreach my $name (@names) {
    foreach my $event (@{$user{$name}{events}}) {
        # do something with $event
    }
}

我使用@{ ... }取消引用events-array,以获取$event中的简单事件列表。

答案 2 :(得分:0)

如何将多个事件数组实例添加到我的哈希?

构建抽象以添加事件。

sub add_event {
  my($user,$name,$event) = @_;

  push @{ $user->{$name}{events} }, $event;
}

在实践中,对它的调用类似于

add_event \%User, "MasterZ", { date => $^T, machine => "host1" };

如何遍历这些数组?

另一种抽象也会对此有所帮助。

use Storable qw/ dclone /;

sub all_events {
  my($user,$name) = @_;

  my $clone = dclone $user->{$name}{events};
  wantarray ? @$clone : $clone;
}

dclone的调用执行deep copy,这使得返回值可以安全地传递给局外人,而不用担心他们会修改您的内部数据。

中使用它
foreach my $event (all_events $name) {
  # do stuff with $event->{date} and $event->{machine} 
}

完整示例

使用以下代码

#! /usr/bin/env perl

use strict;
use warnings;

use Storable qw/ dclone /;

sub add_event {
  my($user,$name,$event) = @_;

  push @{ $user->{$name}{events} }, $event;
}

sub all_events {
  my($user,$name) = @_;

  my $clone = dclone $user->{$name}{events};
  wantarray ? @$clone : $clone;
}

my %User = ( MasterZ => { allowed => 52, denied => 4 } );

add_event \%User, "MasterZ", { date => $^T,     machine => "host1" };
add_event \%User, "MasterZ", { date => $^T + 1, machine => "host2" };

for (all_events \%User, "MasterZ") {
  my($date,$machine) = @{$_}{qw/ date machine /};
  print "$date - $machine\n";
}

# show the internal layout of %User
use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper \%User;

输出类似于

1371671154 - host1
1371671155 - host2
{
  'MasterZ' => {
    'allowed' => 52,
    'events' => [
      {
        'date' => '1371671154',
        'machine' => 'host1'
      },
      {
        'date' => 1371671155,
        'machine' => 'host2'
      }
    ],
    'denied' => 4
  }
}