【问题标题】:How do I shrink an array in Perl?如何在 Perl 中缩小数组?
【发布时间】:2010-09-10 16:58:48
【问题描述】:

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

$#ARRAY = 42;

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

$#$ARRAY[$i] = 42;

【问题讨论】:

  • $# 已弃用,但 $# 与 $#array 不同。我还没有读到任何不推荐使用 $#array 的地方,尽管它令人困惑,我建议不要使用它。

标签: perl arrays


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    你可以的

    splice @array, $length;
    #or
    splice @{$arrays[$i]}, $length;
    

    【讨论】:

    • 第二个例子中有一个虚假的点。
    【解决方案3】:

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

    【讨论】:

    • 这种扩展性很差,特别是当你的数组中有很多元素但只删除了很少的元素时。
    • 好点。我扩展了原始答案以包含该警告并提供一些其他选项。
    【解决方案4】:

    我不知道分配$#ARRAY 已被弃用;来自 5.10.0 的 perldoc perldata 肯定对此一无所知。这是截断数组的最快方法。

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

    splice @ARRAY, 43;
    

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

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

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

    splice @{$ARRAY->[7]}, 43;
    

    【讨论】:

    • 起初我读为“42 - $#ARRAY”。重新阅读后,我意识到您的意思是:“注意,这里使用 43 而不是 42。$#ARRAY 让你......”。
    【解决方案5】:
    • $#array 是数组的最后一个索引
    • $#$array 将是由$array指向的数组的最后一个索引。
    • $#$array[$i] 表示您正在尝试索引标量 - 无法完成。 $#{$array[3]} 在我们尝试引用最后一个索引之前正确解析了主数组的下标。
    • 单独使用

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

      将长度 9 分配给 $array[3] 处的 autovivified 数组。

    • 如有疑问,请使用 Data::Dumper:

      use Data::Dumper;
      $#{$array[3]} = 5;
      $#array       = 10;
      print Dumper( \@array, $array ), "\n";
      

    【讨论】:

      【解决方案6】:

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

      $#Array = 42
      

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

      数组的长度是一个标量值。 您可能会发现 数组@days 通过评估$#days,如在csh 中。然而,这并不是 数组的长度;它是最后一个元素的下标,它是 不同的值,因为通常有第 0 个元素。 分配给 $#days 实际上改变了数组的长度。 缩短数组 这种方式破坏了干预价值。延长一个数组 先前缩短的值不会恢复那些 元素。 (它曾经在 Perl 4 中这样做,但我们不得不打破它以 确保在预期的时候调用了析构函数。)

      【讨论】:

        【解决方案7】:

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

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

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

        【讨论】:

          【解决方案8】:

          有两种解释问题的方式。

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

          到目前为止,大多数答案都集中在前者上。在我看来,最好的答案是 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
          

          可以看到,只有切片操作(复制到新数组)的size比原来的要小。

          这是我用于此分析的代码:

          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));
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-03
            • 2011-11-16
            • 2013-03-07
            • 2021-09-16
            • 1970-01-01
            • 2011-02-13
            相关资源
            最近更新 更多