16

展平多维数组的最简单方法是什么?

4

7 回答 7

35

使用地图的一级展平

$ref = [[1,2,3,4],[5,6,7,8]]; # AoA

@a = map {@$_} @$ref;         # flattens it

print "@a";                   # 1 2 3 4 5 6 7 8
于 2012-12-04T15:49:31.927 回答
17

使用List::Flatten似乎是最简单的:

use List::Flatten;

my @foo = (1, 2, [3, 4, 5], 6, [7, 8], 9);        
my @bar = flat @foo;  # @bar contains 9 elements, same as (1 .. 9)

实际上,该模块只导出一个简单的函数flat,因此您不妨复制源代码

sub flat(@) {
    return map { ref eq 'ARRAY' ? @$_ : $_ } @_;
}

您还可以使其递归以支持多个扁平化级别:

sub flat {  # no prototype for this one to avoid warnings
    return map { ref eq 'ARRAY' ? flat(@$_) : $_ } @_;
}
于 2011-03-02T11:31:02.493 回答
9

简单、最自然的方法是遍历值并使用 @ 运算符“取消引用”/“解包”任何现有的嵌套值以获取组成部分。然后对遇到的每个参考值重复该过程。

这类似于 Viajayenders 解决方案,但适用于尚未在数组引用中的值和任何级别的嵌套:

sub flatten {
  map { ref $_ ? flatten(@{$_}) : $_ } @_;
}

尝试像这样测试它:

my @l1 = [ 1, [ 2, 3 ], [[[4]]], 5, [6], [[7]], [[8,9]] ];
my @l2 = [ [1,2,3,4,5], [6,7,8,9] ];
my @l3 = (1, 2, [3, 4, 5], 6, [7, 8], 9);  # Example from List::Flatten

my @r1 = flatten(@l1);
my @r2 = flatten(@l1);
my @r3 = flatten(@l3);

if (@r1 ~~ @r2 && @r2 ~~ @r3) { say "All list values equal"; }
于 2013-12-03T19:18:19.077 回答
3

如果数据总是像一个例子,我也推荐 List::Flatten。

但数据有超过 2 个嵌套数组,平面不能工作。

@foo = [1, [2, [3, 4, 5]]]

在这种情况下,您应该为它编写递归代码。

下面怎么样。

sub flatten {
  my $arg = @_ > 1 ? [@_] : shift;
  my @output = map {ref $_ eq 'ARRAY' ? flatten($_) : $_} @$arg;
  return @output;
}

my @foo = (1, 2, [3, 4, 5, [6, 7, 8]], 9);
my $foo = [1, 2, [3, 4, 5, [6, 7, 8]], 9];
my @output = flatten @foo;
my @output2 = flatten $foo;
print "@output";
print "@output2";
于 2017-03-21T05:14:58.693 回答
2

扁平化多维数组的最简单方法包括: 1. 数组 2. 数组引用 3. 标量值 4.标量引用

sub flatten {
   map { ref $_ eq 'ARRAY' ? flatten(@{$_}) :
         ref $_ eq 'SCALAR' ? flatten(${$_}) : $_
   } @_;
}

另一个扁平子答案在标量引用上崩溃。

于 2016-06-01T01:24:40.600 回答
0

类似于以下内容:

my $i = 0;

while ($i < scalar(@array)) {
    if (ref @array[$i] eq 'ARRAY') {
        splice @array, $i, 1, @$array[$i];
    } else {
        $i++;
    }
}

我盲目地写了它,不知道它是否真的有效,但你应该明白。

于 2011-03-02T11:32:15.073 回答
0

与 Vijayender 的解决方案相同,但适用于包含 arrayrefs 和标量的混合数组。

$ref = [[1,2,3,4],[5,6,7,8],9,10];
@a = map { ref $_ eq "ARRAY" ? @$_ : $_ } @$ref;
print "@a"

当然,您可以将其扩展为也取消引用 hashrefs:

@a = map { ref $_ eq "ARRAY" ? @$_ : ref $_ eq "HASH" ? %$_: $_ } $@ref;

或使用 grep 清除垃圾:

@a = map { @$_} grep { ref $_ eq 'ARRAY' } @$ref;

从 List::MoreUtils 0.426 开始,我们有一个arrayify函数可以递归地展平数组:

@a = (1, [[2], 3], 4, [5], 6, [7], 8, 9);
@l = arrayify @a; # returns 1, 2, 3, 4, 5, 6, 7, 8, 9

它之前介绍过,但被破坏了。

于 2018-04-11T08:08:32.250 回答