将多维数组转换为一维数组的更好方法

时间:2011-02-09 12:39:00

标签: arrays perl

目前,我使用以下代码将不规则多维数组转换为一维数组。

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是对数组的引用,则使用新数组递归调用它。

有没有更好的方法来解决这类问题?

5 个答案:

答案 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;
'