Вопрос

Как сделать массив короче в 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));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top