简化递归函数
Simplifying recursive function
在绞尽脑汁 recursion 时,我希望通过下面的简单问题更好地理解递归本身,同时本着 TIMTOWTDI 的精神,以其他或更好的方式实现我的目标。
问题很简单,给定一个复杂的 Perl 数据结构,$cds
(保证以 HASH
开始,嗯,这会造成差异吗?),我想遍历 $cds
并删除单级数组。
我从下面开始,效果很好...
sub reduce_1level
{
my $cds = shift;
if (ref $cds eq 'HASH')
{
foreach my $key (keys %$cds)
{
if (ref $cds->{$key} eq 'ARRAY')
{
if (@{$cds->{$key}} == 1)
{
$cds->{$key} = $cds->{$key}[0];
}
else
{
reduce_1level ($cds->{$key});
}
}
elsif (ref $cds->{$key} eq 'HASH')
{
reduce_1level ($cds->{$key});
}
}
}
elsif (ref $cds eq 'ARRAY')
{
foreach (@$cds)
{
reduce_1level ($_) if ref;
}
}
}
...但不知怎的,我觉得代码可以更简单、更短。在针对类似问题针刺堆栈后,我修改为:
sub reduce_1level
{
my $cds = shift;
if (ref $cds eq 'ARRAY')
{
foreach (@$cds)
{
reduce_1level ($_) if ref;
}
}
elsif (ref $cds eq 'HASH')
{
foreach my $key (keys %$cds)
{
if (ref $cds->{$key} eq 'ARRAY' and @{$cds->{$key}} == 1)
{
$cds->{$key} = $cds->{$key}[0];
}
next unless ref $cds->{$key};
reduce_1level ($cds->{$key});
}
}
}
我想知道还有什么或更好的方法可以实现缩进的目标?
忘记复杂性。甚至都不正确。
有些调用处理两级数据结构,因此您应该有重复的代码。但你没有。因此,下面的单元素数组并没有全部被淘汰:
{ foo => [ [ 3 ] ] }
不要试图在同一个调用中处理两个级别。
sub reduce_1level {
our $cds; local *cds = \shift; # alias $cds = shift;
my $reftype = ref($cds)
or return;
if ($reftype eq 'HASH') {
reduce_1level($_) for values %$cds;
}
elsif ($reftype eq 'ARRAY') {
if (@$cds == 1) {
$cds = $cds->[0];
reduce_1level($cds);
} else {
reduce_1level($_) for @$cds;
}
}
else {
die("Unsupported reference type $reftype\n");
}
}
在绞尽脑汁 recursion 时,我希望通过下面的简单问题更好地理解递归本身,同时本着 TIMTOWTDI 的精神,以其他或更好的方式实现我的目标。
问题很简单,给定一个复杂的 Perl 数据结构,$cds
(保证以 HASH
开始,嗯,这会造成差异吗?),我想遍历 $cds
并删除单级数组。
我从下面开始,效果很好...
sub reduce_1level
{
my $cds = shift;
if (ref $cds eq 'HASH')
{
foreach my $key (keys %$cds)
{
if (ref $cds->{$key} eq 'ARRAY')
{
if (@{$cds->{$key}} == 1)
{
$cds->{$key} = $cds->{$key}[0];
}
else
{
reduce_1level ($cds->{$key});
}
}
elsif (ref $cds->{$key} eq 'HASH')
{
reduce_1level ($cds->{$key});
}
}
}
elsif (ref $cds eq 'ARRAY')
{
foreach (@$cds)
{
reduce_1level ($_) if ref;
}
}
}
...但不知怎的,我觉得代码可以更简单、更短。在针对类似问题针刺堆栈后,我修改为:
sub reduce_1level
{
my $cds = shift;
if (ref $cds eq 'ARRAY')
{
foreach (@$cds)
{
reduce_1level ($_) if ref;
}
}
elsif (ref $cds eq 'HASH')
{
foreach my $key (keys %$cds)
{
if (ref $cds->{$key} eq 'ARRAY' and @{$cds->{$key}} == 1)
{
$cds->{$key} = $cds->{$key}[0];
}
next unless ref $cds->{$key};
reduce_1level ($cds->{$key});
}
}
}
我想知道还有什么或更好的方法可以实现缩进的目标?
忘记复杂性。甚至都不正确。
有些调用处理两级数据结构,因此您应该有重复的代码。但你没有。因此,下面的单元素数组并没有全部被淘汰:
{ foo => [ [ 3 ] ] }
不要试图在同一个调用中处理两个级别。
sub reduce_1level {
our $cds; local *cds = \shift; # alias $cds = shift;
my $reftype = ref($cds)
or return;
if ($reftype eq 'HASH') {
reduce_1level($_) for values %$cds;
}
elsif ($reftype eq 'ARRAY') {
if (@$cds == 1) {
$cds = $cds->[0];
reduce_1level($cds);
} else {
reduce_1level($_) for @$cds;
}
}
else {
die("Unsupported reference type $reftype\n");
}
}