在Perl中递归打印数据结构

raj*_*han 5 oop recursion perl

我目前正在学习Perl.我有Perl哈希包含对哈希和数组的引用.散列和数组可以依次包含对其他散列/数组的引用.

我写了一个子程序来递归地解析哈希并用适当的缩进打印它们.虽然例程按预期工作,但我的导师并不相信下面代码的可读性和优雅性.

我非常感谢在这里获得Perl专家的观点,以便对下面的代码进行可能的优化.

这是我的完整代码片段..

# Array of Arrays
$ref_to_AoA = [
     [ "fred", "barney" ],
     [ "george", "jane", "elroy" ],
     [ "homer", "marge", "bart" ],
];


#Array of Hashes
$ref_to_AoH = [ 
{
   husband  => "barney",
   wife     => "betty",
   son      => "bamm bamm",
},
{
   husband => "george",
   wife    => "jane",
   son     => "elroy",
},
];

# Hash of Hashes
$ref_to_HoH = { 
    flintstones => {
        husband   => "fred",
        pal       => "barney",
    },
    jetsons => {
       husband   => "george",
       wife      => "jane",
       "his boy" => "elroy",  # Key quotes needed.
    },
    simpsons => {
       husband   => "homer",
       wife      => "marge",
       kid       => "bart",
    },
};

# Hash which contains references to arrays and hashes
$finalHash = {
   'arrayofArrays' => $ref_to_AoA,
   'arrayofHash' => $ref_to_AoH,
   'hashofHash' => $ref_to_HoH,
};

$string = str($finalHash); 
print "$string\n";

#------------------------------------------------------------------
sub str {
    my $hash = shift;
    my ($space, $newline, $delimiter) = @_;
    $space = "" unless (defined $space);
    $newline = "\n\n\n" unless (defined $newline);
    $delimiter = "\n--------------------------------------------" unless (defined $delimiter);
    my $str = "";

    for (sort keys %{$hash}) {
        my $value = $hash->{$_};
        $str .= "$newline$space$_ == $value$delimiter";
        $str .= recurseErrors($value,$space);
    }
    $str;
}

#------------------------------------------------------------------
sub recurseErrors {
    my $str;
    my ($value,$space) = @_;
    my $ref = ref $value;

    if ($ref eq 'ARRAY') {
        my $i = 0;
        my $isEmpty = 1;
        my @array = @$value;
        $space .= "\t";
        for my $a (@array) {
            if (defined $a) {
                $isEmpty = 0;
                $str .= "\n$space$_\[$i\] :";
                $str .= recurseErrors($a,$space);
            }
            $i++;
        }
        $str .= "= { }" if ($isEmpty);

    } elsif ($ref eq 'HASH') {
        $space .= "\t";
        for my $k (sort keys %$value) {
            if ( ( ref($value->{$k}) eq 'HASH') || (ref $value->{$k} eq 'ARRAY') ) {
                my $val = $value->{$k};
                $str .= "\n\n$space$k == ";
                $str .= "$val";
            }
            else {
                $str .= "\n$space$k == ";
            }
            $str .= recurseErrors($value->{$k},$space);
      }

      # we have reached a scalar (leaf)
    } elsif ($ref eq '') {
        $str .= "$value";
    }
$str
}
#------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

输出:

arrayofArrays == ARRAY(0x9d9baf8)
--------------------------------------------
    arrayofArrays[0] :
        arrayofArrays[0] :fred
        arrayofArrays[1] :barney
    arrayofArrays[1] :
        arrayofArrays[0] :george
        arrayofArrays[1] :jane
        arrayofArrays[2] :elroy
    arrayofArrays[2] :
        arrayofArrays[0] :homer
        arrayofArrays[1] :marge
        arrayofArrays[2] :bart


arrayofHash == ARRAY(0x9d9bba8)
--------------------------------------------
    arrayofHash[0] :
        husband == barney
        son == bamm bamm
        wife == betty
    arrayofHash[1] :
        husband == george
        son == elroy
        wife == jane


hashofHash == HASH(0x9da45f8)
--------------------------------------------

    flintstones == HASH(0x9d9bb48)
        husband == fred
        pal == barney

    jetsons == HASH(0x9d9bbf8)
        his boy == elroy
        husband == george
        wife == jane

    simpsons == HASH(0x9d9bc48)
        husband == homer
        kid == bart
        wife == marge

inn*_*naM 8

  1. 总是用use strict;
  2. 要成为一个好孩子,也要使用use warnings.
  3. 用于子程序的名称应该使子程序的作用变得明显."recurseErrors"有点违反了这个原则.是的,它确实递归.但是有什么错误?
  4. 在每个子例程的第一行,您应该声明并初始化任何参数.recurseErrors首先声明$ str然后声明其参数.
  5. 不要像在str()中那样混合shift和= @_
  6. 您可以考虑将现在称为recurseErrors的内容分解为用于处理数组和散列的专用例程.
  7. 没有必要像第99行和第109行那样引用变量.

除此之外,我认为你的导师那天过得很糟糕.

  • 这是一套很好的规则.我们可以要求原始海报向我们提供他改进任务的最新情况吗?我发现围绕代码风格和设计的讨论非常有趣和启发. (3认同)

dfa*_*dfa 7

也许Data :: Dumper就是你想要的:

use Data::Dumper;

$str = Dumper($foo);
print($str);
Run Code Online (Sandbox Code Playgroud)

  • 我相信他的导师不会对此感到高兴. (8认同)

Tod*_*ner 6

如果您是perl的新手,我建议您通过perl-critic运行代码(还有一个可以从CPAN安装的脚本,通常我将它用作测试,因此无论何时我都可以从命令行运行"make make测试").除了输出之外,您可能还需要更多地分解您的功能.recurseErrors有三种情况可以拆分成子函数(甚至可以放入ref-type到子函数ref的散列).

如果这是一个生产工作,我会使用Data :: Dumper,但听起来这是家庭作业,所以你的老师可能不会太高兴.