Вопрос
Как сделать массив короче в Perl?Я прочитал несколько веб-страниц, указывающих, что я могу назначить:
$#ARRAY = 42;
Я читал, что использование $# устарело.Мне нужно решение, которое будет работать и для массива массивов.Это не сработало:
$#$ARRAY[$i] = 42;
Решение
Я не знаю о назначении $#ARRAY
устарел; perldoc perldata
от 5.10.0 конечно об этом ничего не сказано.Это самый быстрый способ усечь массив.
Если вы хотите что-то более читабельное, используйте splice
:
splice @ARRAY, 43;
(Примечание 43
вместо 42
- $#ARRAY
получает последний индекс массива, тогда как splice
берет длина вместо этого массива).
Что касается работы с массивами массивов, я предполагаю, что вы имеете в виду возможность обрезать вложенный массив по ссылке?В этом случае вы хотите:
$#{$ARRAY->[7]} = 42;
или
splice @{$ARRAY->[7]}, 43;
Другие советы
Ваши возможности практически безграничны (здесь я изложил пять подходов), но ваша стратегия будет диктоваться именно вашими конкретными потребностями и целями.(во всех примерах @array преобразуется так, чтобы в нем было не более $N элементов)
[РЕДАКТИРОВАТЬ]
Как отмечали другие, способ, предложенный в исходном вопросе, на самом деле не устарел и обеспечивает самое быстрое, краткое, но не обязательно самое читаемое решение. Это также имеет побочный эффект расширения массива, содержащего менее $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
А $#
переменная устарела, но $#array
особенность нет.
Чтобы использовать $#array
синтаксис произвольного выражения, которое возвращает ссылку на массив, выполните $#{ EXPR }
.
Увидеть бесценное: http://perlmonks.org/?node=References+quick+reference
По сути, вы сами дали канонический ответ.Вы сокращаете массив, устанавливая последний индекс:
$#Array = 42
Обозначение $#Foo для обозначения последнего индекса в массиве абсолютно нет устарел.Аналогично, назначение ему также не будет устаревшим.Цитирование документации perldata:
Длина массива является скалярной величиной. Вы можете найти длину массива @days, оценив $#дней, как в csh.Однако это не длина массива;Это индекс последнего элемента, который является другим значением, поскольку обычно существует 0 -й элемент. Присвоение $#Days фактически меняет длину массива. Сокращение массива таким образом разрушает промежуточные значения.Удлинение массива, которое было ранее сокращено, не восстанавливает значения, которые были в этих элементах.(Раньше это делало это в Perl 4, но мы должны были сломать это, чтобы убедиться, что деструкторы были вызваны, когда ожидали.)
- $#массив - это последний индекс массива.
- $#$массив было бы последний индекс массива указал на по $array.
- $#$array[$i] означает, что вы пытаетесь проиндексировать скаляр — это невозможно.$#{$array[3]} правильно разрешает индексацию основного массива, прежде чем мы попытаемся сослаться на последний индекс.
Используется отдельно
$#{$array[3]} = 9;
присваивает длину 9 самооживленный массив в $array[3].
В случае сомнений используйте Data::Dumper:
use Data::Dumper; $#{$array[3]} = 5; $#array = 10; print Dumper( \@array, $array ), "\n";
$#{$ARRAY[$i]} = 42;
Ты мог бы сделать
splice @array, $length;
#or
splice @{$arrays[$i]}, $length;
Есть два способа интерпретации вопроса.
- Как уменьшить длину массива?
- Как уменьшить объем памяти, потребляемый массивом?
Большинство ответов до сих пор сосредоточены на первом.На мой взгляд, лучший ответ на этот вопрос – это сращивание функция.Например, чтобы удалить 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));
}