多次元配列を平坦化する最も簡単な方法は何ですか?
7 に答える
マップを使用した 1 レベルの平坦化
$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
使用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(@$_) : $_ } @_;
}
最も簡単で自然な方法は、値を反復処理し、@ 演算子を使用して、既存のネストされた値を「逆参照」/「アンパック」して、構成部分を取得することです。次に、検出されたすべての参照値に対してプロセスを繰り返します。
これは 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"; }
データが常に例のようなものである場合は、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";
1. 配列 2. 配列参照 3. スカラー値 4.スカラー参照
sub flatten {
map { ref $_ eq 'ARRAY' ? flatten(@{$_}) :
ref $_ eq 'SCALAR' ? flatten(${$_}) : $_
} @_;
}
他の flatten sub answer は、スカラー参照でクラッシュします。
次のようなもの:
my $i = 0;
while ($i < scalar(@array)) {
if (ref @array[$i] eq 'ARRAY') {
splice @array, $i, 1, @$array[$i];
} else {
$i++;
}
}
私はやみくもに書いたので、実際に機能するかどうかはわかりませんが、アイデアを得る必要があります.
Vijayender のソリューションと同じですが、arrayref とスカラーを含む混合配列で機能します。
$ref = [[1,2,3,4],[5,6,7,8],9,10];
@a = map { ref $_ eq "ARRAY" ? @$_ : $_ } @$ref;
print "@a"
もちろん、これを拡張してハッシュリファレンスを逆参照することもできます:
@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
以前紹介しましたが壊れていました。