我目前正在学习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
}
#------------------------------------------------------------------
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
答案 0 :(得分:8)
use strict
; use warnings
。除此之外,我认为你的导师那天过得不好。
答案 1 :(得分:7)
也许Data::Dumper就是你想要的:
use Data::Dumper;
$str = Dumper($foo);
print($str);
答案 2 :(得分:6)
如果您不熟悉perl,我建议您通过perl-critic运行代码(还有一个可以从CPAN安装的脚本,通常我将它用作测试,以便从命令行运行每当我做“测试”)。除了输出之外,您可能还需要更多地分解您的功能。 recurseErrors有三种情况可以拆分成子函数(甚至可以放入ref-type的散列到子函数ref)。
如果这是一份制作工作,我会使用Data::Dumper,但听起来这是作业,所以你的老师可能不会太高兴。
答案 3 :(得分:3)
以下是一个简单的示例,说明为什么您的代码不易阅读:
$delimiter = "\n--------------------------------------------" unless (defined $delimiter);
您可以使用defined or
运算符:
$delimiter //= "\n" . '-' x 44;
如果你担心早期的Perls:
defined $delimeter or $delimeter = "\n" . '-' x 44;
离开右边距的条件对我来说已经足够了,不能阅读剩下的代码。
答案 4 :(得分:1)
我的猜测是他不喜欢你
str
函数中的哈希值。 str
,但它从未计入最终结果。这些是我能够很快看到的问题。
答案 5 :(得分:1)
你可以分离掉处理数组和哈希的代码块。
sub recurse{
...
recurse_A(@_) if $ref eq 'ARRAY';
recurse_H(@_) if $ref eq 'HASH';
...
}
sub recurse_A{ ... }
sub recurse_H{ ... }
我建议你开始这样的子程序,除非你有充分的理由不这样做。
sub example{
my( $one, $two, $three, $optional_four ) = @_;
(如果你这样做,那么Komodo,至少,将能够弄清楚你的子程序的参数是什么)
很少有理由将变量放入仅包含变量的字符串中。
"$var" eq $var;
我能想到的唯一一次,当我使用一个具有重载""
函数的对象时,我想获取字符串,而不是获取对象。
package My_Class;
use overload
'""' => 'Stringify',
;
sub new{
my( $class, $name ) = @_;
my $self = bless { name => $name }, $class;
return $self;
}
sub Stringify{
my( $self ) = @_;
return $self->{name};
}
my $object = My_Class->new;
my $string = "$object";
答案 6 :(得分:1)
我之前一直在努力解决这个问题,并在这里找到了解决方法。我几乎使用了这里发布的解决方案,但发现了一个更合适的解决方案(对我来说无论如何)。阅读深度优先递归 here。
上述文章中的sub与包含其他Hashes,Arrays或Scalars的引用完美配合。但它没有打印Hash密钥名称,所以我稍微修改了它:
#!/usr/bin/perl
#
# See:
#
# http://perldesignpatterns.com/?DepthFirstRecursion
#
use strict;
use warnings;
my %hash = (
'a' => {
'one' => 1111,
'two' => 222,
},
'b' => [ 'foo', 'bar' ],
'c' => 'test',
'd' => {
'states' => {
'virginia' => 'richmond',
'texas' => 'austin',
},
'planets' => [ 'venus','earth','mars' ],
'constellations' => ['orion','ursa major' ],
'galaxies' => {
'milky way' => 'barred spiral',
'm87' => 'elliptical',
},
},
);
&expand_references2(\%hash);
sub expand_references2 {
my $indenting = -1;
my $inner; $inner = sub {
my $ref = $_[0];
my $key = $_[1];
$indenting++;
if(ref $ref eq 'ARRAY'){
print ' ' x $indenting,'ARRAY:';
printf("%s\n",($key) ? $key : '');
$inner->($_) for @{$ref};
}elsif(ref $ref eq 'HASH'){
print ' ' x $indenting,'HASH:';
printf("%s\n",($key) ? $key : '');
for my $k(sort keys %{$ref}){
$inner->($ref->{$k},$k);
}
}else{
if($key){
print ' ' x $indenting,$key,' => ',$ref,"\n";
}else{
print ' ' x $indenting,$ref,"\n";
}
}
$indenting--;
};
$inner->($_) for @_;
}
答案 7 :(得分:0)