лучший способ для преобразования многомерного массива в одномерный массив - PullRequest
1 голос
/ 09 февраля 2011

В настоящее время я использую следующий код для преобразования неправильного многомерного массива в одномерный массив.

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);
        }
}

Это основано на рекурсии, где я проверяю каждый элемент. Если элемент является ссылкой на массив, то вызывать его рекурсивно с новым массивом.

Есть ли лучший способ решить эту проблему?

Ответы [ 5 ]

7 голосов
/ 09 февраля 2011

Прежде всего ваша функция никогда не должна возвращать данные, изменяя глобальную переменную. Вместо этого верните список.

Что касается эффективности, 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. Мы все знаем бесполезность спора о едином истинном стиле скобок. Но, по крайней мере, я собираюсь предложить вам уменьшить отступ в 8 пробелов. Существует исследование в этой области, и было показано, что понимание кода улучшается с отступами в диапазоне 2-4. Прочитайте Код завершен для подробностей. Для молодых людей не имеет значения, где вы находитесь в этом диапазоне, но пожилые программисты, чье зрение улучшится, найдут лучший отступ. Прочитайте Советы по Perl , чтобы узнать больше.

3 голосов
/ 09 февраля 2011

Используйте 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 голосов
/ 09 февраля 2011

Обычно рекурсию лучше заменять итерацией. Для общих методов, см. Книгу 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;
    }
}

Причина, по которой это лучше, в том, что рекурсивные реализации:

  • Риск, связанный с переполнением стека, если вложенных уровней слишком много

  • Менее эффективен из-за стоимости рекурсивных вызовов

0 голосов
/ 09 февраля 2011

Я использовал это в прошлом. Этот код находится в командной строке, но вы можете поместить код в одинарные кавычки в ваш файл .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;
'
0 голосов
/ 09 февраля 2011

В общем, это единственный способ сделать это.

Вы можете немного оптимизировать свой код, только снова вызывая getList (), когда вы встретите ArrayRef.Если вы найдете обычное значение, вы можете вставить его прямо в @mylist вместо повторного запуска getList ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...