1

通常我可以考虑哈希和数组的所有不同复杂性,但我似乎无法让这个工作......

这是我的数组:

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

这是我希望哈希的样子

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

我需要遍历每个用户(当前有效),然后在该用户内遍历每个事件。

2个问题:

  1. 如何将事件数组的多个实例添加到我的哈希中?
  2. 如何循环遍历这些数组?

任何帮助,将不胜感激。

4

3 回答 3

3

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

  • 它由连续的正整数范围索引,以0.
  • 它将标量作为值
  • 它们用方括号索引,例如$array[0] = $val.

另一方面,哈希具有属性

  • 它由唯一的字符串索引。
  • 键值对没有保证顺序。
  • 它将标量作为值保存。
  • 它们用卷曲索引,例如$hash{"some key"} = $val. 如果键是有效标识符,则引号是可选的:$hash{some_key} = $val.

散列和数组都不是标量,但您可以使用一元运算符进行引用\,它是一个标量。

不要被其他语言使用“关联数组”这个名称来表示 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
于 2013-06-19T19:26:11.183 回答
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.

于 2013-06-19T19:27:49.063 回答
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 - 主机1
1371671155 - 主机2
{
  'MasterZ' => {
    '允许' => 52,
    '事件' => [
      {
        '日期' => '1371671154',
        '机器' => '主机1'
      },
      {
        '日期' => 1371671155,
        '机器' => '主机2'
      }
    ],
    '拒绝' => 4
  }
}
于 2013-06-19T19:41:31.090 回答