2008-09-18 8 views
10

Comment rendre un tableau plus court en Perl? J'ai lu quelques pages Web indiquant que je peux assigner:Comment réduire un tableau en Perl?

$#ARRAY = 42; 

J'ai lu que l'utilisation de $ # est dépréciée. J'ai besoin d'une solution qui fonctionne aussi pour un ensemble de tableaux. Cela n'a pas fonctionné:

$#$ARRAY[$i] = 42; 
+0

$ # est dépréciée, mais # $ n'est pas la même chose que le tableau $ #. Je n'ai lu nulle part que le tableau $ # est obsolète, même s'il est confus et je recommanderais de ne pas l'utiliser. –

Répondre

16

Je ne suis pas au courant de l'affectation de $#ARRAY étant obsolète; perldoc perldata de 5.10.0 ne dit certainement rien à ce sujet. C'est le moyen le plus rapide de tronquer un tableau.

Si vous voulez quelque chose d'un peu plus lisible, utilisez splice:

splice @ARRAY, 43; 

(Remarque 43 au lieu de 42-$#ARRAY vous obtient le dernier indice du tableau, alors que splice taks la longueur du tableau au lieu). En ce qui concerne les tableaux de tableaux, je suppose que vous voulez dire que vous pouvez tronquer un tableau imbriqué via une référence?Dans ce cas, vous voulez:

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

ou

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

Vous pouvez faire

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

Vous avez un point faux dans votre second exemple. –

10

Vos options sont illimitées près (je l'ai indiqué cinq approches ici), mais votre stratégie sera dictée par exactement ce que vos besoins et objectifs spécifiques. (Tous les exemples convertiront @array ne pas avoir plus de N $ éléments)


[EDIT]

Comme d'autres l'ont souligné, la manière suggérée dans la question initiale est en fait pas dépréciée, et fournit la solution la plus rapide, la plus rapide, mais pas nécessairement la plus lisible. Il a également l'effet secondaire d'étendre une gamme de moins de N $ éléments avec des éléments vides:

$#array = $N-1; 

Code moins:

#best for trimming down large arrays into small arrays 
@array = $array[0..($N-1)]; 

plus efficace pour tailler un petit nombre de d'un grand tableau:

#This is a little less expensive and clearer 
splice(@array, $n, @#array); 

Indésirable dans presque un cas ll, à moins que vous aimez vraiment supprimer():

#this is the worst solution yet because it requires resizing after the delete 
while($N-1 < $#array) 
{ 
    delete(array[$i]); 
} 

Utile si vous avez besoin du reste de la liste dans l'ordre inverse:

#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 
} 

Utile pour un gain de temps à la longue:

#don't put more values into the array than you actually want 
+0

Cela échoue très mal, surtout quand vous avez beaucoup d'éléments dans votre tableau mais n'en supprimez que peu. –

+0

Bon point. J'ai élargi la réponse originale pour inclure cette mise en garde et pour fournir quelques autres options. – Frosty

2
  • $ # tableau est le dernier indice du tableau.
  • $ # $ tableau serait le dernier index d'un tableau pointé à par $ array.
  • $ # $ array [$ i] signifie que vous essayez d'indexer un scalaire - cela ne peut pas être fait. $ # {$ array [3]} résout correctement l'indice du tableau principal avant d'essayer de référencer le dernier index.
  • Utilisé seul

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

    affecte une longueur de 9 au tableau autovivified dans $ array [3].

  • En cas de doute, utilisez Data :: Dumper:

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

vous a donné essentiellement la réponse canonique vous-même. Vous raccourcissez un tableau en réglant le dernier indice:

$#Array = 42 

La notation $ # Foo pour désigner le dernier indice du tableau est absolument pas dépréciée. De même, l'affectation ne sera pas non plus déconseillée. Citant la documentation perldata:

La longueur d'un tableau est une valeur scalaire. Vous pouvez trouver la longueur de tableau @days en évaluant $ # jours, comme dans csh. Cependant, ce n'est pas la longueur du tableau; c'est l'indice du dernier élément, qui est une valeur différente de puisqu'il y a normalement un 0ème élément. Affectation à $ # jours modifie réellement la longueur de la matrice. Raccourcir un tableau détruit ainsi les valeurs intermédiaires. L'allongement d'un tableau précédemment raccourci ne récupère pas les valeurs contenues dans les éléments . (Il fut le faire en Perl 4, mais nous avons dû briser ce à faire Destructeurs sûr ont été appelés au moment prévu.)

0

Il y a deux façons d'interpréter la question.

  • Comment réduire la longueur de la matrice?
  • Comment réduire la quantité de mémoire consommée par la baie?

La plupart des réponses se concentrent jusqu'à présent sur le premier. À mon avis, la meilleure réponse à cela est la fonction épissure. Par exemple, pour éliminer les 10 éléments de la fin:

splice @array, -10; 

Cependant, en raison de la façon dont Perl gère la mémoire pour les tableaux, la seule façon de garantir qu'un réseau prend moins de mémoire est de le copier dans un nouveau tableau (et que la mémoire de l'ancien tableau soit récupérée). Pour cela, j'aurais tendance à penser à utiliser une opération tranche. Par exemple, pour supprimer 10 éléments:

@new = @old[ 0 .. $#old - 10 ] 

Voici une comparaison des différentes approches pour un ensemble d'éléments 500 (en utilisant 2104 octets):

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 

Vous pouvez voir que seule l'opération de découpage (copié sur un nouveau tableau) a une taille inférieure à que l'original.

Voici le code que j'utilisé pour cette analyse:

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