【问题标题】:dereferencing a nested hash in perl在 perl 中取消引用嵌套哈希
【发布时间】:2016-06-17 07:27:11
【问题描述】:
#!/usr/bin/perl

use strict;
use warnings;

my %ani_hash = (
    'machine_results' => [
        {
            'status'  => 'Failed install',
            'machine' => '23.73.134.235',
            'seconds' => '20',
            'try'     => '1'
        },
        {
            'status'  => 'Failed install',
            'machine' => '23.73.134.140',
            'seconds' => '20',
            'try'     => '1'
        }
    ],
    'description' => 'MC-5897'
);

get_elements( \%ani_hash );

sub get_elements
{
    my $hashref1 = shift;

    my %hashref2 = %$hashref1;
    print "%hashref1\n";

    foreach my $machineresult ( keys %hashref2 ) {
        foreach my $machineresult2 ( keys %{ $hashref2{$machineresult} } ) {
            print "$hashref2{$machineresult}{$machineresult2}\n";
        }
    }
}

Output: 

    HASH(0x1e9fe58)
    Not a HASH reference at ./hashref.pl line 62.
    Can't use string ("MC-5897") as a HASH ref while "strict refs" in use at ./hashref.pl line 62.

我想遍历所有键值对并获取它们的值。 我不想使用 dumper 方法来获取值,我想通过循环方法来获取这些值。任何帮助,将不胜感激。谢谢

我这样做是为了解决问题并获取“machine_results”的内容。

print "description: $hashref2{description}\n";

foreach my $machineresult( sort keys%hashref2){
    foreach my $array (@{ $hashref2{$machineresult} }){
        foreach my $array1( sort keys%{$array} ){
            print "key is $array1 and it's value is $array->{$array1}`",
                  "enter code here`\n";    
        }
        print "\n";
    }
}

【问题讨论】:

  • $hashref2{$machineresult} 是对数组的引用,所以 keys %{ $hashref2{$machineresult} } 没有意义。你想要@{ $hashref2{$machineresult} }
  • 在我看来,你的%ani_hash 总是有 2 个元素,machine_resultsdescription,而你只想遍历数组(参考) machine_results,对吧?
  • @DavidO:我对你的讽刺有疑问,以及暗示 recursion 是处理这种结构的唯一方法
  • 感谢@ikegami 的帮助,我已经编辑了我的帖子。如果这看起来不错,请告诉我。
  • 自己运行代码,你会看到Can't use string ("MC-5897") as an ARRAY ref while "strict refs" in use at ./so.pl line 36. 那就是foreach my $array 。发生这种情况是因为代码试图将$hashref2{'description'} 解释为不是的arrayref。这是一个字符串。

标签: perl hash hashmap


【解决方案1】:

我假设您的 %ani_hash 始终有 2 个元素,machine_resultsdescription,并且您只想遍历 machine_results 中的数组(参考)。如果这是真的,以下内容会有所帮助:

sub get_elements
{
    my $hashref = shift;

    print "Description: $hashref->{description}\n";

    my $count=0;
    foreach my $result ( @{ $hashref->{machine_results} } ) {
        print $count++, ': ';
        foreach my $key ( sort keys %{$result} ) {
            print "$key=$result->{$key}, ";
        }
        print "\n";
    }
}

get_elements( \%ani_hash );

输出:

Description: MC-5897
0: machine=23.73.134.235, seconds=20, status=Failed install, try=1, 
1: machine=23.73.134.140, seconds=20, status=Failed install, try=1, 

解释:

  • $hashref->{machine_results} 是您的机器结果的数组引用。
  • @{ $hashref->{machine_results} } 将其取消引用到您可以迭代的数组,所以
  • $result 是这些数组项之一,它又是对哈希的引用
  • 使用%{$result},它被取消引用到一个散列,我们遍历(排序的)键

当然,这假设您的数据结构是这样的,即 machine_results 包含一个内部带有 hashrefs 的 arrayref。

【讨论】:

  • 感谢@Perl Dog 的帮助。我修改了代码并编辑了帖子。让我知道它是否看起来不错。
【解决方案2】:

您的代码未正确解包嵌套哈希。对于散列%h = ('key' => [1, 2]),与key 关联的值是对(匿名)数组的引用,因此是标量。见文末链接。

要获取数组的内容,我们需要取消引用它。那么这些数组元素本身就是 hashrefs,它们也需要被取消引用

sub get_elements 
{    
    my %hash = %{ $_[0] };
    print "description: $hash{'description'}\n";
    foreach my $mach_res (keys %hash)
    {   
        next if $mach_res eq 'description';
        foreach my $elem ( @{$hash{$mach_res}} ) { 
            my %mach_detail = %$elem;
            print "\t---\n";
            foreach my $key (sort keys %mach_detail) {
                print "\t$key => $mach_detail{$key}\n";
            }   
        }           
    }   
}

hashref 用于获取新的“in-sub”副本%hash。这是对错误的一些保护,因为原始数据无法更改。但是,如果您希望 subs 直接更改他们获得参考的数据,那么您需要使用参考本身。这打印

描述:MC-5897 --- 机器 => 23.73.134.235 秒 => 20 状态 => 安装失败 试试 => 1 --- 机器 => 23.73.134.140 秒 => 20 状态 => 安装失败 试试 => 1

代码将处理除“描述”之外的任何其他键。如果您想对齐打印输出,您可以先拉出其中一个键(单词)的最大长度,然后使用printf了解详情。

use List::Util qw(max);
foreach my $elem ( @{$hash{$mach_res}} ) {
    my %mach_detail = %$elem;
    my $max_len = max( map { length } keys %mach_detail );
    print "\t---\n";
    foreach my $key (sort keys %mach_detail) {
        #print "\t$key => $mach_detail{$key}\n";
        printf("\t%${max_len}s => %s\n", $key, $mach_detail{$key});
    }
}

模块List::Util用于获取max功能。现在你得到了

描述:MC-5897 --- 机器 => 23.73.134.235 秒 => 20 状态 => 安装失败 试试 => 1 --- 机器 => 23.73.134.140 秒 => 20 状态 => 安装失败 试试 => 1

一些相关的近期 SO 资源:nested hash/arrayarray of hashes

【讨论】:

  • 感谢@zdim 提供的参考资料和代码:)。一定会查的。
  • @hitman99 非常欢迎。在您从综合资源中彻底阅读之前,这些东西的良好参考是宝贵的。幸运的是,SO 有很多很好的、实用的、中肯的介绍。完成我的编辑,以便很好地打印您的整个结构。我希望这对你有用。
  • 这当然很有帮助。我同意你关于 SO 的观点。谢谢你:)
  • 我不能以某种方式标记你@zdim 我不知道为什么:\
  • 我已经对您的答案表示赞同,但似乎我需要更多的徽章才能这样做(鉴于我是新来的)。 :)
猜你喜欢
  • 1970-01-01
  • 2016-04-25
  • 1970-01-01
  • 2020-12-09
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
相关资源
最近更新 更多