13

如何在 Perl 中使数组更短?我阅读了一些网页,表明我可以分配:

$#ARRAY = 42;

我读到不推荐使用 $# 。我也需要一个适用于数组数组的解决方案。这没有用:

$#$ARRAY[$i] = 42;
4

8 回答 8

19

我不知道分配$#ARRAY被弃用;perldoc perldata从 5.10.0 开始,当然什么也没说。这是截断数组的最快方法。

如果您想要更具可读性的内容,请使用splice

splice @ARRAY, 43;

(注意43而不是42-$#ARRAY获取数组的最后一个索引,而获取数组splice长度)。

至于处理数组数组,我假设您的意思是能够通过引用截断嵌套数组?在这种情况下,您需要:

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

或者

splice @{$ARRAY->[7]}, 43;
于 2008-09-18T14:20:03.353 回答
10

您的选择几乎是无限的(我在这里概述了五种方法),但您的策略将完全取决于您的具体需求和目标。(所有示例都将 @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
于 2008-09-18T14:17:22.907 回答
7

$#变量已弃用,但该$#array功能未弃用。

$#array在产生数组引用的任意表达式上使用语法,请执行$#{ EXPR }.

查看无价之宝:http ://perlmonks.org/?node=References+quick+reference

于 2008-09-18T16:20:01.473 回答
5

您基本上自己给出了规范的答案。通过设置最后一个索引来缩短数组:

$#Array = 42

表示数组中最后一个索引的 $#Foo 符号绝对不会被弃用。同样,分配给它也不会被弃用。引用 perldata 文档:

数组的长度是一个标量值。 您可以通过评估 $#days 来找到数组 @days 的长度,就像在 csh 中一样。但是,这不是数组的长度;它是最后一个元素的下标,这是一个不同的值,因为通常有第 0 个元素。 分配给 $#days 实际上会更改数组的长度。 以这种方式缩短数组会破坏中间值。延长先前缩短的数组不会恢复这些元素中的值。(它曾经在 Perl 4 中这样做,但我们必须打破它以确保在预期的时候调用析构函数。)

于 2008-09-18T14:48:28.700 回答
2
  • $#array 是数组的最后一个索引
  • $#$array将是$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";
    
于 2008-09-18T14:26:02.747 回答
0

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

于 2008-09-18T14:10:57.040 回答
0

你可以做

splice @array, $length;
#or
splice @{$arrays[$i]}, $length;
于 2008-09-18T14:12:44.417 回答
0

有两种解释问题的方法。

  • 如何减少数组的长度?
  • 如何减少数组消耗的内存量?

到目前为止,大多数答案都集中在前者上。在我看来,最好的答案是拼接功能。例如,要从末尾删除 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));
}
于 2008-09-18T18:20:39.920 回答