0

我有一个问题希望有人能提供帮助(为了解释我的问题而进行了简化)。

我有以下数组散列的散列(我认为这就是它的本质?)

数据结构

{
  Cat => {
    Height => ["Tiny"],
  },
  Dog => {
    Colour => ["Black"],
    Height => ["Tall"],
    Weight => ["Fat", "Huge"],
  },
  Elephant => {
    Colour => ["Grey"],
    Height => ["Really Big"],
    Weight => ["Fat", "Medium", "Thin"],
  },
}

我想要做什么

下面的程序将打印整个数据结构。我想用这种方式来做

my %h;

for my $animal (keys %h) {
   print "$animal\n";
   for my $attribute ( keys %{$h{$animal}} ) {
        print "\t $attribute\n";
        for my $i (0 .. $#{$h{$animal}{$attribute}} ) {
            print "\t\t$h{$animal}{$attribute}[$i]\n";
        }    
   }   
}          

我遇到的问题

我正在尝试访问数据结构的特定部分。例如,我只想打印出Height每个动物的数组,因为我不关心本示例中的其他Colour属性Weight

我确信对此有一个简单的答案,并且我知道我需要指定Height零件,但是正确的做法是什么?我尝试了多种我认为不会成功的方法。

4

5 回答 5

2

在您的代码中,而不是使用循环遍历所有属性

for my $attribute ( keys %{ $h{$animal} } ) { ... }

只用你感兴趣的。像这样

for my $animal (keys %h) {
   print "$animal\n";
   for my $attribute ( 'Height' ) {
        print "\t $attribute\n";
        for my $i (0 .. $#{$h{$animal}{$attribute}} ) {
            print "\t$h{$animal}{$attribute}[$i]\n";
        }    
   }   
}          

我会选择循环遍历 heights 数组的内容而不是索引,使代码看起来像这样:

for my $animal (keys %h) {
    print "$animal\n";
    print "\t\t$_\n" for @{ $h{$animal}{Height} };
}          
于 2013-04-18T10:27:52.433 回答
2

快速查看您的数据结构:它是数组哈希的哈希!哇。头脑正式炸开了锅。

这是打印所有数据的快速方法:

use feature qw(say);

# Working with a Hash of Hash of Arrays
for my $animal (keys %h) {
    say "Animal: $animal";
    # Dereference: Now I am talking about a hash of arrays
    my %animal_attributes = %{ $h{$animal} };
    for my $attribute (keys %animal_attributes) {
        # Dereference: Now I am talking about just an array
        my @attribute_value_list = @{ $animal_attributes{$attribute} };
        say "\tAttribute: $attribute - " . join ", ", @attribute_value_list;
    }
}

注意我使用取消引用。我不必进行取消引用,但它使代码更易于使用。我不必考虑我的各种水平。我知道我的动物是属性的散列,而这些属性是属性值的数组。通过使用取消引用,它可以让我保持直截了当。

现在,假设您只想打印出所需属性的列表。您可以exists在尝试打印之前使用该函数查看该属性是否存在。

use feature qw(say);
use constant DESIRED_ATTRIBUTES => qw(weight height sex_appeal);

# Working with a Hash of Hash of Arrays
for my $animal (keys %h) {
    say "Animal: $animal";
    # Dereference: Now I am talking about a hash of arrays
    my %animal_attributes = %{ $h{$animal} };
    for my $attribute ( DESIRED_ATTRIBUTES ) {
        if ( exists $animal_attributes{$attribute} ) {
            # Dereference: Now I am talking about just an array
            my @attribute_value_list = @{ $animal_attributes{$attribute} }; 
            say "\tAttribute: $attribute - " . join ", ", @attribute_value_list;
        }
    }
}

相同的代码,我只是添加了一个 if 子句。

当您进入这些复杂的数据结构时,使用面向对象设计可能会更好。Perl 有一个关于 OOP Perl的优秀教程。如果你使用它,你可以定义一类动物并有各种方法来提取你想要的数据。它使维护变得更加容易,并允许您勇敢地创建更复杂的数据结构,而无需担心跟踪您的位置。

于 2013-04-18T15:42:43.003 回答
1

我认为有时直接使用该值会更容易,如果它是对另一个结构的引用。您可以执行以下操作:

my $height = "Height";

while (my ($animal, $attr) = each %h) {
    print "$animal\n";
    print "\t$height\n";
    print "\t\t$_\n" for @{ $attr->{$height} };
}

使用主键的值,您可以跳过引用的一步,直接进入Height属性。下面的输出是您在原始代码中使用的格式。

输出:

Elephant
        Height
                Really Big
Cat
        Height
                Tiny
Dog
        Height
                Tall
于 2013-04-18T11:41:09.290 回答
1

假设您的变量名为 %h:

foreach my $animal (keys %h) {
   my $heights = $h{$animal}->{Height}; #gets the Height array
   print $animal, "\n";
   foreach my $height( @$heights ) {
      print "  ", $height, "\n";
   }
}
于 2013-04-18T09:57:07.220 回答
0

我想我已经解决了,发现我做错了什么?

我认为应该是这样的:

my %h;

for my $animal (keys %h) {
      print "$animal\n";
      for my $i (0 .. $#{$h{$animal}{Height}} ) {
          print "\t\t$h{$animal}{Height}[$i]\n";
      }    
}   
于 2013-04-18T10:28:34.633 回答