2008-09-18 10 views
10

¿Cómo hago una matriz más corta en Perl? He leído algunas páginas web que indica que puedo asignar:¿Cómo reduzco una matriz en Perl?

$#ARRAY = 42; 

leí que el uso de $ # es obsoleto. Necesito una solución que también funcione para una matriz de matrices. Esto no funcionó:

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

$ # es obsoleto, pero $ # no es lo mismo que $ # matriz. No he leído en ningún lugar que $ # array está en desuso, aunque es confuso y recomendaría uno en contra de usarlo. –

Respuesta

16

No estoy al tanto de la asignación de $#ARRAY obsoleto; perldoc perldata desde 5.10.0 ciertamente no dice nada al respecto. Es la forma más rápida de truncar una matriz.

Si quieres algo un poco más fácil de leer, usar splice:

splice @ARRAY, 43; 

(Nota 43 en lugar de 42-$#ARRAY le consigue el último índice de la matriz, mientras que splice TAKS el longitud de la matriz en lugar).

En cuanto a trabajar en matrices de matrices, ¿supongo que quiere decir que puede truncar una matriz anidada a través de una referencia?En ese caso, usted quiere:

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

o

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

Usted podría hacer

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

Tiene un punto espúreo en su segundo ejemplo. –

10

Sus opciones son ilimitadas cerca (que he descrito cinco enfoques aquí), pero su estrategia será dictada por exactamente cuáles son sus necesidades y objetivos específicos. (Todos los ejemplos convertirán @array a tener no más de $ N elementos)


[EDIT]

Como otros han señalado, la forma en que se sugiere en la pregunta original en realidad no es obsoleta, y se proporciona la solución más rápida, más barata, pero no necesariamente la más fácil de leer. También tiene el efecto secundario de la expansión de una matriz de menos de $ N elementos con los elementos vacíos:

$#array = $N-1; 

código mínimo:

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

más eficiente para el recorte de un pequeño número de de una gran matriz:

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

Indeseable en casi una casos ll, a menos que realmente amas a eliminar():

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

Es útil si se necesita el resto de la lista en orden inverso:

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

útil para ahorrar tiempo en el largo plazo:

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

Eso se escala bastante mal, especialmente cuando tienes muchos elementos en tu matriz pero solo eliminas algunos. –

+0

Buen punto. Expandí la respuesta original para incluir esa advertencia y proporcionar algunas otras opciones. – Frosty

2
  • $ # matriz es el último índice de la matriz.
  • $ # $ array sería el último índice de una matriz apuntando a por $ array.
  • $ # $ array [$ i] significa que intenta indexar un escalar: no se puede hacer. $ # {$ array [3]} resuelve correctamente la subscripción de la matriz principal antes de intentar hacer referencia al último índice.
  • Usado solo

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

    asigna una longitud de 9 a la matriz autovivified en $ array [3].

  • En caso de duda, el uso de datos :: Dumper:

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

Esencialmente dio la respuesta canónica a sí mismo. A acortar una serie fijando el último índice:

$#Array = 42 

El Foo notación $ # para denotar el último índice de la matriz es absolutamente no obsoleta. Del mismo modo, la asignación a él tampoco será desaprobada. Citando la documentación de perldata:

La longitud de una matriz es un valor escalar. Puede encontrar la longitud de array @days evaluando $ # días, como en csh. Sin embargo, esta no es la longitud de la matriz; es el subíndice del último elemento, que es un valor diferente ya que normalmente hay un 0 ° elemento. Asignando a $ # días realmente cambia la longitud de la matriz. Acortar una matriz de esta manera destruye los valores intermedios. Alargar una matriz que fue previamente acortada no recupera los valores que estaban en esos elementos . (Se utiliza para hacerlo en Perl 4, pero tuvimos que romper este a asegurarse de que los destructores fueron llamados cuando se espera.)

0

Hay dos maneras de interpretar la cuestión.

  • Cómo reducir la longitud de la matriz?
  • Cómo reducir la cantidad de memoria consumida por la matriz?

La mayoría de las respuestas se centran en la primera. En mi opinión, la mejor respuesta es la función de empalme . Por ejemplo, para eliminar 10 elementos desde el extremo:

splice @array, -10; 

Sin embargo, debido a la forma Perl administra la memoria para las matrices, la única manera de garantizar que una matriz toma menos memoria es para copiarlo en una nueva matriz (y dejar que se recupere la memoria de la antigua matriz). Para esto, tendería a pensar en utilizar una operación de corte. Por ejemplo, para eliminar 10 elementos:

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

He aquí una comparación de los diferentes enfoques para una matriz de 500 elementos (utilizando 2104 bytes):

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 

se puede ver que sólo la operación de troceado (copia en una nueva matriz) tiene un tamaño más pequeño que el original.

Aquí está el código que he usado para este análisis:

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