Perl: Какой самый простой способ сгладить многомерный массив? - PullRequest
15 голосов
/ 02 марта 2011

Какой самый простой способ сгладить многомерный массив?

Ответы [ 7 ]

36 голосов
/ 04 декабря 2012

Один уровень сглаживания с использованием карты

$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
15 голосов
/ 02 марта 2011

Использование List::Flatten кажется самым простым:

use List::Flatten;

my @foo = (1, 2, [3, 4, 5], 6, [7, 8], 9);
# @foo contains 6 elements, 2 of them are array references

my @bar = flat @foo;
# @bar contains 9 elements, same as (1 .. 9)

Используйте List::Flatten::Recursive, чтобы сделать это рекурсивно.

9 голосов
/ 03 декабря 2013

Самый простой способ - это перебирать значения и использовать оператор @ для «разыменования» / «распаковки» любых существующих вложенных значений для получения составных частей. , Затем повторите процесс для каждого найденного эталонного значения.

Это похоже на решение 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"; }
3 голосов
/ 21 марта 2017

если данные всегда в качестве примера, я рекомендую также List :: Flatten.

, но данные имеют более 2 вложенных массивов, flat не может работать.

как @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";
2 голосов
/ 01 июня 2016

Самый простой способ сгладить многомерный массив, если он включает в себя: 1. массивы 2. ссылки на массивы 3. скалярные значения 4. скалярные ссылки

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

Другой сглаживать подответвылетает при скалярных ссылках.

0 голосов
/ 11 апреля 2018

То же, что и решение Vijayender, но будет работать со смешанными массивами, содержащими arrayrefs и scalar.

$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

Она была представлена ​​ранеено был сломан.

0 голосов
/ 02 марта 2011

Что-то вроде:

my $i = 0;

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

Я написал это вслепую, понятия не имею, работает ли это на самом деле, но вы должны понять это.

...