循环遍历数组哈希散列中的已知元素

时间:2013-04-18 09:51:31

标签: arrays perl loops hash nested

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

我有以下哈希的数组哈希(我认为这是什么呢?)

数据结构

{
  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数组,因为我不关心此示例中的其他ColourWeight属性。

我确信这有一个简单的答案,我知道我需要指定Height部分,但这样做的正确方法是什么?我尝试了多种方法,我认为这种方法没有成功。

5 个答案:

答案 0 :(得分: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";
        }    
   }   
}          

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

for my $animal (keys %h) {
    print "$animal\n";
    print "\t\t$_\n" for @{ $h{$animal}{Height} };
}          

答案 1 :(得分: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;
    }
}

注意我使用解除引用。我没有 来进行取消引用,但它使代码更容易使用。我不必考虑我的各种水平。我知道我的动物是 hash 属性,这些属性是属性值的数组。通过使用解除引用,它可以让我保持正确。

现在,假设您只打印出所需属性列表。您可以使用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上有一个excellent tutorial。如果你使用它,你可以定义一类动物,并有各种方法来提取你想要的数据。它使维护变得更加容易,并且您可以勇敢地创建更复杂的数据结构,而无需担心跟踪您的位置。

答案 2 :(得分: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";
   }
}

答案 3 :(得分: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

答案 4 :(得分: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";
      }    
}