需要修改 perl Deep::Hash::Utils

问题描述

我对 perl 很陌生。我正在尝试使用来自 CPAN 的以下代码。

my $C;

# Recursive version of C<each>;
sub reach {
    my $ref = shift;


    if (ref $ref eq 'HASH') {


        if (defined $C->{$ref}{v}) {
            if (ref $C->{$ref}{v} eq 'HASH') {
                if (my @rec = reach($C->{$ref}{v})) {
                    return ($C->{$ref}{k},@rec);
                } 
            } elsif (ref $C->{$ref}{v} eq 'ARRAY') {
                if (my @rec = reach($C->{$ref}{v})) {
                    if (defined $C->{$ref}{k}) {
                        return $C->{$ref}{k},@rec;
                    }
                    return @rec;
                } 

            }
            undef $C->{$ref};
        } 


        if (my ($k,$v) = each %$ref) {
            $C->{$ref}{v} = $v;
            $C->{$ref}{k} = $k;
            return ($k,reach($v));
        }

        return ();


    } elsif (ref $ref eq 'ARRAY') {


        if (defined $C->{$ref}{v}) {
            if (ref $C->{$ref}{v} eq 'HASH' || 
                ref $C->{$ref}{v} eq 'ARRAY') {

                if (my @rec = reach($C->{$ref}{v})) {
                    if (defined $C->{$ref}{k}) {
                        return $C->{$ref}{k},@rec;
                    }
                    return @rec;
                } 
            } 
        }



        if (my $v = $ref->[$C->{$ref}{i}++ || 0]) {
            $C->{$ref}{v} = $v;
            return (reach($v));
        }

        return ();
    }
    return $ref;
}

输入:

bar => {cmd_opts => { gld_upf => ['abc','def']} }

电流输出:

[bar,cmd_opts,gld_upf,abc]

[bar,def]

期望输出:

[bar,['abc','def']]

另外,这段代码中使用了哪些概念? 有什么书/课程我可以学习吗?

解决方法

另外,这段代码中使用了哪些概念?有什么书/课程我可以学习吗?

您在Deep::Hash::Utils CPAN 模块中提到的代码主要是处理嵌套数据结构。

有几个地方可以阅读这些内容:

在最基本的情况下,在这些嵌套数据结构中,每个节点都具有以下类型之一:

  • 标量
  • 哈希引用
  • 数组引用

反过来,arrayref 指向的数组中的值可以是 scalar/hashref/arrayref 类型。 arrayref 指向的哈希值也是如此,它可以是 scalar/hashref/arrayref 类型。

这会产生一个 tree-like 结构。遍历这样一棵树的算法是depth-first search 其中需要一些额外的逻辑来检查节点的类型,并根据类型决定如何进一步向下处理树。

为了进行平行,所有这些与遍历文件系统层次结构并没有太大区别(参见link1link2)。

关于 Perl 资源的 bigger list called perlres 可用。


在这种特定情况下,Deep::Hash::Utils 中的函数 reach 充当迭代器,它返回从根向下到每个叶子的所有路径。 每当找到叶子的 @path 时,它的元素都会与另一个名为 @output 的列表并排比较,并且存在三种情况:

  • 那个位置没有元素,所以我们存储它
  • 元素是相等的,所以我们跳过它们
  • 元素不同,所以我们将它们合并到一个列表中
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Deep::Hash::Utils qw/reach/;

my $input = { bar => {cmd_opts => { gld_upf => ['abc','def']} } };

my @output = ();

while (my @path = reach($input)) {
    for(my $i=0;$i<=$#path;$i++){
        if(defined $output[$i]) {
            if(ref($output[$i]) eq "") {
                if($output[$i] eq $path[$i]) {
                    next;
                };
                my $e1 = $output[$i];
                my $e2 = $path[$i];
                $output[$i] = [$e1,$e2];
            }elsif(ref($output[$i]) eq "ARRAY"){
                push @{$output[$i]},$path[$i];
            };
        } else {
            $output[$i] = $path[$i];
        };
    };
}

print Dumper \@output;

输出:

$VAR1 = [
          'bar','cmd_opts','gld_upf',[
            'abc','def'
          ]
        ];

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...