Как сжать массив в 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));
}