目前,我使用以下代码将不规则多维数组转换为一维数组。
my $array = [0,
[1],
2,
[3, 4, 5],
[6,
[7, 8, 9 ],
],
[10],
11,
];
my @mylist;
getList($array);
print Dumper (\@mylist);
sub getList
{
my $array = shift;
return if (!defined $array);
if (ref $array eq "ARRAY")
{
foreach my $i (@$array)
{
getList($i);
}
}
else
{
print "pushing $array\n";
push (@mylist, $array);
}
}
这是基于递归,我在检查每个元素。如果element是对数组的引用,则使用新数组递归调用它。
有没有更好的方法来解决这类问题?
答案 0 :(得分:7)
首先,您的函数不应该通过修改全局变量来返回数据。改为返回一个列表。
至于效率,Perl具有令人惊讶的大型函数调用开销。因此,对于大型数据结构,我更喜欢非递归方法。像这样:
use Data::Dumper;
my $array = [
0,
[1],
2,
[3, 4, 5],
[6, [7, 8, 9 ]],
[10],
11,
];
my @mylist = get_list($array);
print Dumper (\@mylist);
sub get_list {
my @work = @_;
my @result;
while (@work) {
my $next = shift @work;
if (ref($next) eq 'ARRAY') {
unshift @work, @$next;
}
else {
push @result, $next;
}
}
return @result;
}
请注意,我在这里使用的格式符合perlstyle的建议。我们都知道争论One True Brace Style是徒劳的。但至少我建议你减少8个空格缩进。对此进行了研究,并且已经证明代码理解在2-4空间范围内具有缩进。有关详细信息,请阅读Code Complete。对于年轻人而言,你在这个范围内并不重要,但是视力正在发展的年长程序员会找到更好的缩进。有关详情,请阅读Perl Best Practices。
答案 1 :(得分:3)
使用CPAN。在你知道这是一个问题之前,不要担心递归开销。
#!/usr/bin/perl
use strict;
use warnings;
use List::Flatten::Recursive;
my $array = [
0,
[1],
2,
[3, 4, 5],
[6, [7, 8, 9 ]],
[10],
11,
];
my @result = flat($array);
print join(", ", @result), "\n";
答案 2 :(得分:2)
通常用迭代替换递归通常会更好。对于一般技术,请参阅高阶Perl书(自由开放)第5章,在本例中:
my @stack = ($array);
my @flattened;
while (@stack) {
my $first = shift @stack;
if (ref($first) eq ref([])) {
push @stack, @$first; # Use unshift to keep the "order"
} else {
push @flattened, $first;
}
}
它更好的原因是因为递归实现:
如果嵌套级别太多,则风险会进入堆栈溢出
由于递归电话费用而效率较低
答案 3 :(得分:0)
通常,这是实现此目的的唯一方法。
当您遇到ArrayRef时,只需再次调用getList()即可优化代码。如果找到常规值,可以直接将其推送到@mylist而不是重新运行getList()。
答案 4 :(得分:0)
我过去曾经用过这个。此代码位于命令行中,但您可以将代码放在.pl文件中的单引号中
$ perl -le'
use Data::Dumper;
my @array = ( 1, 2, 3, [ 4, 5, 6, [ 7, 8, 9 ] ], [ 10, 11, 12, [ 13, 14, 15 ] ], 16, 17, 18 );
sub flatten { map ref eq q[ARRAY] ? flatten( @$_ ) : $_, @_ }
my @flat = flatten @array;
print Dumper \@flat;
'