加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 从散列键列表反序列化嵌套散列

发布时间:2020-12-16 06:23:30 所属栏目:大数据 来源:网络整理
导读:我有一个字符串,我想“unflatten”或“tree-ify”;也就是说,我想从此开始: F=8|A_C=3|A_B=2|D_G_H=11|D_B=2|E=5 对此: { A = { B = 2,C = 3,},D = { B = 2,G = { H = 11,E = 5,F = 8,} 我的策略是分别处理每个管道分隔的字段,并通过=符号分成一个键/值对:
我有一个字符串,我想“unflatten”或“tree-ify”;也就是说,我想从此开始:

F=8|A_C=3|A_B=2|D_G_H=11|D_B=2|E=5

对此:

{
  A => {
    B => 2,C => 3,},D => {
     B => 2,G => {
       H => 11,E => 5,F => 8,}

我的策略是分别处理每个管道分隔的字段,并通过=符号分成一个键/值对:

sub unflatten {
    my ($data) = @_;
    my @fields = split /|/,$data;
    my $result = {};

    for my $datum (@fields) {
            my ($key,$value) = split /=/,$datum;
            $result->{&processline($key)} = $value;
    }
    return $result;
}

我在processline函数中尝试了一些递归魔法:

sub processline {
    my ($key) = @_;

    my ($first,$rest) = split /_/,$key,2; # split key into at most 2 parts
    if($rest) {
            return { $first => &processline($rest) }; 
            # if the key is nested,there will be something in $rest
            # so recursively process the smaller $rest,and build up the result hashref
    }
    else {
            return $first;
    }
}

不幸的是,这不起作用:

my $header = "F=8|A_C=3|A_B=2|D_G_H=11|D_B=2|E=5";
use Data::Dumper;
print Dumper &unflatten($header);

当我这样做时,我得到:

$VAR1 = {
      'F' => '8','HASH(0xe9af60)' => '2','HASH(0xe9ae28)' => '11','E' => '5','HASH(0xe9af90)' => '3','HASH(0xe9ae40)' => '2'
    };

有人可以解释递归解决方案背后的思考过程,还是建议我的Perl出错了?令人沮丧的是,我能够很容易地得出这个功能的反转(扁平化).

解决方法

我相信使用简单的for循环比使用递归更直接.您选择的方法无法工作,因为它仅使用processline返回的单个键来分配值,并且无法创建多级哈希.

递归解决方案的工作方式是获取哈希引用,键列表和值,以及定义

unflatten($hash,'key1_key2_key3_key4','value')

unflatten($hash->{key1},'key2_key3_key4','value')`

该程序演示了一个普通循环解决方案它使用一个指针$hash,它从结果哈希的根开始,并在列表中的每个键之后向前移动一个级别.

sub unflatten {

  my $result = {};

  for my $item (split /|/,$_[0]) {

    my ($keys,$item;
    my @keys = split /_/,$keys;
    my $hash = $result;

    while (@keys > 1) {
      my $key = shift @keys;
      $hash->{$key} ||= {};
      $hash = $hash->{$key};
    }

    $hash->{$keys[0]} = $value;
  }

  return $result;
}

产量

$VAR1 = {
      'A' => {
               'C' => '3','B' => '2'
             },'F' => '8','D' => {
               'G' => {
                        'H' => '11'
                      },'E' => '5'
    };

更新

现在我回到了键盘,这是一个递归的解决方案.它导致与原始哈希相同的哈希

use strict;
use warnings;

use Data::Dumper;

my $data = 'F=8|A_C=3|A_B=2|D_G_H=11|D_B=2|E=5';

my $result = {};
unflatten2($result,$_) for split /|/,$data;
print Dumper $result;

sub unflatten2 {
  my ($hash,$data) = @_;

  if ($data =~ /_/) {
    my ($key,$data;
    unflatten2($hash->{$key} ||= {},$rest);
  }
  else {
    my ($key,$val) = split /=/,$data;
    $hash->{key} = $val;
  }
}

更新

您可能也对Data::Diver模块感兴趣,该模块适用于此类情况,尽管文档有点笨拙

以下是使用它的解决方案的外观

use strict;
use warnings;

use Data::Diver qw/ DiveVal /;
use Data::Dumper;

my $data = 'F=8|A_C=3|A_B=2|D_G_H=11|D_B=2|E=5';

my $result = {};    

for (split /|/,$data) {
  my ($keys,$val) = split /=/;
  DiveVal($result,split /_/,$keys) = $val;
}

print Dumper $result;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读