Как сжать массив в Perl?

Как сделать массив короче в Perl? Я прочитал несколько веб-страниц, указывающих, что я могу назначить:

$#ARRAY = 42;

Я читал, что использование $# устарело. Мне нужно решение, которое будет работать и для массива массивов. Это не помогло:

$#$ARRAY[$i] = 42;

Ответ 1

Мне не известно о назначении $#ARRAY устаревших; perldoc perldata от 5.10.0, конечно, ничего не говорит об этом. Это самый быстрый способ усечения массива.

Если вам нужно что-то более читаемое, используйте splice:

splice @ARRAY, 43;

(Примечание 43 вместо 42 - $#ARRAY получает последний индекс массива, тогда как splice принимает длину массива).

Что касается работы с массивами массивов, я предполагаю, что вы имеете в виду возможность обрезать вложенный массив через ссылку? В этом случае вы хотите:

$#{$ARRAY->[7]} = 42;

или

splice @{$ARRAY->[7]}, 43;

Ответ 2

Ваши варианты почти безграничны (я изложил здесь пять подходов), но ваша стратегия будет продиктована именно вашими конкретными потребностями и целями. (все примеры преобразуют @array, чтобы иметь не более $N элементов)


[EDIT]

Как указывали другие, способ, предложенный в исходном вопросе, фактически не устарел, и он обеспечивает самое быстрое, но не обязательно наиболее читаемое решение. Он также имеет побочный эффект для расширения массива из менее чем $N элементов с пустыми элементами:

$#array = $N-1;

Меньший код:

#best for trimming down large arrays into small arrays
@array = $array[0..($N-1)];

Наиболее эффективен для обрезки небольшого числа большого массива:

#This is a little less expensive and clearer
splice(@array, $n, @#array);

Нежелательно почти во всех случаях, если вы действительно не любите delete():

#this is the worst solution yet because it requires resizing after the delete
while($N-1 < $#array)
{
   delete(array[$i]);
}

Полезно, если вам нужна оставшаяся часть списка в обратном порядке:

#this is better than deleting because there is no resize
while($N-1 < $#array)
{
    pop @array;
    #or, "push $array2, pop @array;" for the reverse order remainder
}

Полезно для экономии времени в долгосрочной перспективе:

#don't put more values into the array than you actually want

Ответ 3

Переменная $# устарела, но функция $#array отсутствует.

Чтобы использовать синтаксис $#array для произвольного выражения, которое дает ссылку на массив, сделайте $#{ EXPR }.

Смотрите бесценный: http://perlmonks.org/?node=References+quick+reference

Ответ 4

Вы сами дали канонический ответ. Вы сокращаете массив, устанавливая последний индекс:

$#Array = 42

Обозначение $# Foo для обозначения последнего индекса в массиве абсолютно не устарело. Точно так же присвоение ему также не будет устаревшим. Цитирование документации perldata:

Длина массива - это скалярное значение. Вы можете найти длину array @days, оценивая $# days, как в csh. Однако это не длина массива; его индекс последнего элемента, который является другое значение, поскольку обычно используется 0-й элемент. Присвоение $# days фактически изменяет длину массива. Сокращение массива таким образом, уничтожаются промежуточные значения. Удлинение массива, который был ранее сокращенный, не восстанавливает значения, которые были в этих элементы. (Раньше это делалось на Perl 4, но мы должны были разбить это на убедитесь, что деструкторы были вызваны, когда ожидалось.)

Ответ 5

  • $# array - последний индекс массива.
  • $# $array будет последним индексом массива, на который указывает $array.
  • $# $array [$ i] означает, что вы пытаетесь индексировать скаляр - не может быть сделано. $# {$ array [3]} правильно разрешает подписку основного массива, прежде чем мы попытаемся ссылаться на последний индекс.
  • Используется отдельно

    $# {$ array [3]} = 9;

    присваивает длину 9 массиву autovivified в $array [3].

  • Если вы сомневаетесь, используйте Data:: Dumper:

    use Data::Dumper;
    $#{$array[3]} = 5;
    $#array       = 10;
    print Dumper( \@array, $array ), "\n";
    

Ответ 6

$# {$ ARRAY [$ i]} = 42;

Ответ 7

Вы могли бы сделать

splice @array, $length;
#or
splice @{$arrays[$i]}, $length;

Ответ 8

Существует два способа интерпретации вопроса.

  • Как уменьшить длину массива?
  • Как уменьшить объем памяти, потребляемой массивом?

Большинство ответов до сих пор сосредоточены на первом. На мой взгляд, лучшим ответом на это является функция сращивания. Например, чтобы удалить 10 элементов из конца:

splice @array, -10;

Однако из-за того, как Perl управляет памятью для массивов, единственный способ гарантировать, что массив занимает меньше памяти, - это скопировать его в новый массив (и вернуть память старого массива). Для этого я хотел бы подумать об использовании операции среза. Например, чтобы удалить 10 элементов:

@new = @old[ 0 .. $#old - 10 ]

Здесь приведено сравнение различных подходов для массива 500 элементов (с использованием 2104 байта):

  original: length  500 => size 2104
     pound: length  490 => size 2208
    splice: length  490 => size 2104
    delete: length  490 => size 2104
     slice: length  490 => size 2064

Вы можете видеть, что только операция среза (скопирована в новый массив) имеет меньший размер, чем оригинал.

Вот код, который я использовал для этого анализа:

use strict;
use warnings;
use 5.010;
use Devel::Size qw/size/;

my @original = (1 .. 500);
show( 'original', \@original );

my @pound = @original;
$#pound = $#pound - 10;
show( 'pound', \@pound );

my @splice = @original;
splice(@splice,-10);
show( 'splice', \@splice);

my @delete = @original;
delete @delete[ -10 .. -1 ];
show( 'delete', \@delete );

my @slice = @original[0 .. $#original - 10];
show( 'slice', \@slice);

sub show {
    my ($name, $ref) = @_;
    printf( "%10s: length %4d => size %d\n", $name, scalar @$ref, size($ref));
}