Perl嵌套数据结构

时间:2014-03-20 20:07:44

标签: perl perl-data-structures hash-reference

我无法将大脑包裹在正在返回的数据结构中...我需要做的是检查结果,如果是HASH则修改字段。在'结果'中,任何具有KEY为'null'且值为'1'的HASH的KEY需要更改为'0'。下面我从返回的Data :: Dumper粘贴了一些示例数据。在这种情况下,我想在四个不同的地方更改数据。我已经处理了一段时间而且无法理解......任何帮助都表示赞赏。

$VAR1 = {
  'results' => [
    {
      'admin' => 'DUMMY DATA',
      'object' => 'DUMMY DATA',
      'ifDescr' => 'DUMMY DATA',
      'total_device' => {
        'null' => '1'
      },
      'ifIndex' => 'DUMMY DATA',
      'oper' => 'DUMMY DATA',
      'percent_online' => 'DUMMY DATA',
      'device_offline' => {
        'null' => '1'
      },
      'dataflow' => 'DUMMY DATA',
      'Map' => 'DUMMY DATA',
      'ifdevice' => 'DUMMY DATA',
      'device_online' => 'DUMMY DATA'
    },
    {
      'admin' => 'DUMMY DATA',
      'object' => 'DUMMY DATA',
      'ifDescr' => 'DUMMY DATA',
      'total_device' => {
        'null' => '1'
      },
      'ifIndex' => 'DUMMY DATA',
      'oper' => 'DUMMY DATA',
      'percent_online' => 'DUMMY DATA',
      'device_offline' => {
        'null' => '1'
      },
      'dataflow' => 'DUMMY DATA',
      'Map' => 'DUMMY DATA',
      'ifdevice' => 'DUMMY DATA',
      'device_online' => 'DUMMY DATA'
    }
  ]
};

3 个答案:

答案 0 :(得分:1)

  

我无法将大脑缠绕在正在返回的数据结构中......

您已经接受了答案,我只想澄清Data::Dumper输出的解释:

  • 每个{...}表示对哈希的引用。您会看到key => value,作为哈希元素。
  • 每个[...]代表对数组的引用。您会看到value,为数组元素。

分开你拥有的东西:

$VAR = $VAR1 = {
   'results' => [
        ....       # This is an array reference
    ]

或者     $ VAR-> {results} = [];

这是一个单键results的哈希值。散列具有对数组的引用作为其值。到目前为止:

$VAR1 = {
  'results' => [  # This is the [0] element in my array
    {
        ...       # This is a hash reference
    }
]
[                 # This is the [1] element in my array
    {
        ...       # This is a hash reference
    }

在此数组中,有两个值,每个值指向一个哈希引用:

$VAR->{results}->[0] = {};
$VAR->{results}->[1] = {};

在每个数组中,哈希引用都有12个键和值:

  • 管理员
  • 数据流
  • devices_online
  • 物体
  • ifDescr
  • ifDevice
  • 的ifIndex
  • OPER
  • percent_online
  • 地图
  • 这些都有参考....
    • total_devices
    • devices_offline

前10个只是键/值对。最后两个是对具有单个键/值对的另一个散列的引用。键是null。我认为这是某种错误。

现在我可以参考其中一个这样的项目:

$VAR->{results}->[1]->{ifIndex} = 'DUMMY DATA';

假设当前结构,这是一种在循环中引用它的方法:

my $VAR = some_function()                # Returns a reference to a hash.

for my $result ( keys %{ $VAR } ) {     # Dereference the hash reference...
   say "Key for results is '$result'";  # Only one result. And that's 'result'...
   my @array = $VAR->{$result};         # Dereference the array reference that hash points to
   for my $element ( 0..$#array ) {     # Now we get to the two elements in the array
      say qq(Looking at element #$element);
      my $hash_key = $array[$element];  # he hash reference that the array points to
      my %inner_hash = %{ $hash_key };  # Another dereference...
      for my $key ( keys %inner_hash" ) {
        say "\$VAR->{$result}->[$element]->{%hash_key} = "
           . $VAR->{$result}->[$element]->{%hash_key};
      }
   }
}

这不会完全奏效,因为total_devicedevice_offline再次是哈希引用。我应该在我的内部循环中做一个异常,如果其中任何一个是我的内部哈希的关键,我需要做另一个解引用来获取哈希。我会让你解决这个问题。

当然,我知道我的结构,所以我可以编写一个程序结构来处理它。如果我不知道我的数据结构的布局,我将不得不使用ref命令来查明我是在引用散列还是数组,并相应地取消引用和循环。这几乎是Data::Dumper所做的。

我通常认为这样一个复杂的结构来自 class 构造函数,我希望在这样的Data ::中看到对象的 blessed 类名。翻斗车转储。在这种情况下,我会告诉你使用该类的方法,而不是解构数据结构并自己进行。这是面向对象设计中的禁忌。

您应始终将数据结构视为黑盒子。你不应该仅仅因为Perl没有提供 blinds 来将结构和方法标记为 private 而达到峰值。这仍然是不礼貌的举止。

但是,Data :: Dumper没有显示类的名称,因此它不是类对象。 Ogle远离数据结构。

查看Perl Reference Tutorial,了解这是否有助于澄清情况。

答案 1 :(得分:0)

我并没有完全明白你的意思"任何关键是HASH" - 可能你的意思是:"任何值为HASH"的值。 无论如何,如果我做对了,也许这个脚本可能会有所帮助。 它将递归检查数据结构内的哈希值,并根据需要更改值。

#!/usr/bin/env perl
use strict;
use warnings;

use Data::Dumper;

# test data given in the post
my $VAR1 = {...}; # truncated

sub recursive_change {
    my $hash = shift;
    foreach my $key (keys %{$hash}) {
        my $value = $hash->{$key};
        if ($key eq 'null' && $value eq '1') { # or 1, depends
            $hash->{$key} = '0'; # or 0, depends
        }
        elsif (ref($value) eq 'HASH') {
            recursive_change($value);
        }
    }
}


foreach my $elem (@{$VAR1->{results}}) {
    recursive_change($elem);
}

print Data::Dumper->new([ $VAR1 ],[ '*VAR1' ])->Sortkeys(1)->Dump();

编辑:将整个哈希设置为0:

sub recursive_change {
    my $hash = shift;
    foreach my $key (keys %{$hash}) {
        my $value = $hash->{$key};
        if (ref($value) eq 'HASH') {
            if ($value->{null} eq '1') {
                $hash->{$key} = 0;
            }
            else {
                change($value);
            }
        }
    }
}

虽然不是最好的解决方案,但它确实有效。

答案 2 :(得分:0)

听起来你需要遍历结果的元素,并且对于每个元素,如果任何值是hashref,并且hashref具有键值对null => 1,将其替换为null => 0

应该看起来像:

# iterate through results
for my $result (@$results) {
    # check each hash in results for nested hashes
    for my $key (keys(%$result)) {
        # if the value here is a hashref, do stuff
        if(ref $result->{$key} eq 'HASH') {
            # the stuff to be done 
            # specifically, replace null => 1 with null => 0
            $result->{$key}->{null} = 0 if $result->{$key}->{null} == 1;
        }
    }
}

当我测试它时,它似乎做你想要的(用null => 0替换4个null => 1的实例)。我确信这是一个更漂亮的方式来写这个。