Как мне сжать массив в Perl? - PullRequest
       43

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

10 голосов
/ 18 сентября 2008

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

$#ARRAY = 42;

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

$#$ARRAY[$i] = 42;

Ответы [ 8 ]

16 голосов
/ 18 сентября 2008

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

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

splice @ARRAY, 43;

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

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

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

или

splice @{$ARRAY->[7]}, 43;
10 голосов
/ 18 сентября 2008

Ваши возможности практически безграничны (я изложил пять подходов здесь), но ваша стратегия будет продиктована именно вашими конкретными потребностями и целями. (все примеры преобразуют @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
7 голосов
/ 18 сентября 2008

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

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

См. Бесценное: http://perlmonks.org/?node=References+quick+reference

5 голосов
/ 18 сентября 2008

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

$#Array = 42

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

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

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

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

    присваивает длину 9 массиву с автовывозом в массиве $ [3].

  • В случае сомнений используйте Data :: Dumper:

    use Data::Dumper;
    $#{$array[3]} = 5;
    $#array       = 10;
    print Dumper( \@array, $array ), "\n";
    
0 голосов
/ 18 сентября 2008

Есть два способа интерпретации вопроса.

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

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

splice @array, -10;

Однако из-за того, как Perl управляет памятью для массивов, единственный способ гарантировать, что массив занимает меньше памяти, - это скопировать его в новый массив (и позволить памяти старого массива освободиться). Для этого я бы подумал об использовании операции slice . Например, чтобы удалить 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));
}
0 голосов
/ 18 сентября 2008

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

splice @array, $length;
#or
splice @{$arrays[$i]}, $length;
0 голосов
/ 18 сентября 2008

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

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