Este es el comando perllol que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.
PROGRAMA:
NOMBRE
perllol - Manipulación de matrices de matrices en Perl
DESCRIPCIÓN
Declaración y Acceda a of Matrices of Matrices
La estructura de datos de dos niveles más simple para construir en Perl es una matriz de matrices, a veces
casualmente llamado una lista de listas. Es razonablemente fácil de entender y casi
todo lo que se aplica aquí también se aplicará más adelante con los datos más sofisticados
.
Una matriz de una matriz es solo una matriz antigua regular @AoA a la que puede acceder con dos
subíndices, como $ AoA [3] [2]. Aquí hay una declaración de la matriz:
utilizar 5.010; # para que podamos usar say ()
# asignar a nuestra matriz, una matriz de referencias de matriz
@AoA = (
["fred", "barney", "guijarros", "bambam", "dino",],
["george", "jane", "elroy", "judy",],
["homer", "bart", "marge", "maggie",],
);
digamos $ AoA [2] [1];
bart
Ahora debe tener mucho cuidado de que el tipo de soporte exterior sea redondo, es decir, un
paréntesis. Eso es porque está asignando a una @array, por lo que necesita paréntesis. Si
que querías allí No para ser un @AoA, sino solo una referencia a él, podrías hacer
algo más como esto:
# asignar una referencia a una matriz de referencias de matriz
$ ref_to_AoA = [
["fred", "barney", "guijarros", "bambam", "dino",],
["george", "jane", "elroy", "judy",],
["homer", "bart", "marge", "maggie",],
];
decir $ ref_to_AoA -> [2] [1];
bart
Observe que el tipo de corchete exterior ha cambiado, por lo que nuestra sintaxis de acceso también ha cambiado.
Eso es porque, a diferencia de C, en Perl no se pueden intercambiar libremente matrices y referencias.
al mismo. $ ref_to_AoA es una referencia a una matriz, mientras que @AoA es una matriz propiamente dicha.
Asimismo, $ AoA [2] no es una matriz, sino una matriz ref. Entonces, ¿cómo es que puedes escribir esto?
$ AoA [2] [2]
$ ref_to_AoA -> [2] [2]
en lugar de tener que escribir estos:
$ AoA [2] -> [2]
$ ref_to_AoA -> [2] -> [2]
Bueno, eso se debe a que la regla es que solo en los corchetes adyacentes (ya sean cuadrados o rizados),
puede omitir la flecha de eliminación de referencias del puntero. Pero no puedes hacerlo por el
primero si es un escalar que contiene una referencia, lo que significa que $ ref_to_AoA siempre
lo necesita.
Creciendo Su Propia
Eso está muy bien para la declaración de una estructura de datos fija, pero ¿y si quisiera?
para agregar nuevos elementos sobre la marcha o construirlos completamente desde cero?
Primero, veamos cómo leerlo desde un archivo. Esto es algo así como agregar una fila en un
hora. Asumiremos que hay un archivo plano en el que cada línea es una fila y cada palabra una
elemento. Si está tratando de desarrollar una matriz @AoA que contenga todos estos, aquí está el derecho
forma de hacer eso:
while (<>) {
@tmp = dividir;
presione @AoA, [@tmp];
}
También podría haberlo cargado desde una función:
por $ i (1 .. 10) {
$ AoA [$ i] = [somefunc ($ i)];
}
O es posible que haya tenido una variable temporal con la matriz en ella.
por $ i (1 .. 10) {
@tmp = alguna función ($ i);
$ AoA [$ i] = [@tmp];
}
Es importante que se asegure de utilizar el constructor de referencia de matriz "[]". Eso es porque
esto no funcionaría:
$ AoA [$ i] = @tmp; # ¡INCORRECTO!
La razón por la que no hace lo que quiere es porque asignar una matriz con nombre como esa a un
escalar está tomando una matriz en contexto escalar, lo que significa que solo cuenta el número de
elementos en @tmp.
Si está ejecutando bajo "uso estricto" (y si no lo está, ¿por qué diablos no lo está?),
tendrás que agregar algunas declaraciones para hacerlo feliz:
uso estricto
mi (@AoA, @tmp);
while (<>) {
@tmp = dividir;
presione @AoA, [@tmp];
}
Por supuesto, no necesita que la matriz temporal tenga un nombre en absoluto:
while (<>) {
presione @AoA, [dividir];
}
Tampoco tienes que usar empujar(). Podrías hacer una asignación directa si supieras
donde querías ponerlo:
my (@AoA, $ i, $ línea);
por $ i (0 .. 10) {
$ línea = <>;
$ AoA [$ i] = [dividir "", $ línea];
}
o incluso solo
mi (@AoA, $ i);
por $ i (0 .. 10) {
$ AoA [$ i] = [dividir "", <>];
}
En general, debe tener cuidado con el uso de funciones que potencialmente podrían devolver listas en
contexto escalar sin indicarlo explícitamente. Esto sería más claro para los casuales.
lector:
mi (@AoA, $ i);
por $ i (0 .. 10) {
$ AoA [$ i] = [split "", escalar (<>)];
}
Si quisiera tener una variable $ ref_to_AoA como referencia a una matriz, tendría que hacer
algo como esto:
while (<>) {
empujar @ $ ref_to_AoA, [dividir];
}
Ahora puede agregar nuevas filas. ¿Qué hay de agregar nuevas columnas? Si estás lidiando con solo
matrices, a menudo es más fácil usar una asignación simple:
por $ x (1 .. 10) {
por $ y (1 .. 10) {
$ AoA [$ x] [$ y] = func ($ x, $ y);
}
}
por $ x (3, 7, 9) {
$ AoA [$ x] [20] + = func2 ($ x);
}
No importa si esos elementos ya están allí o no: con gusto creará
para usted, estableciendo los elementos intermedios en "undef" según sea necesario.
Si solo quisiera agregar a una fila, tendría que hacer algo un poco más divertido:
# agregar nuevas columnas a una fila existente
empuja @ {$ AoA [0]}, "wilma", "betty"; # deref explícito
Antes de Perl 5.14, esto ni siquiera compilaba:
presione $ AoA [0], "wilma", "betty"; # deref implícito
¿Cómo? Porque una vez, el argumento para empujar() tenía que ser una matriz real, no
solo una referencia a uno. Eso ya no es cierto. De hecho, la línea marcada como "deref implícito"
arriba funciona bien, en este caso, para hacer lo que hizo el que dice explícitamente deref.
La razón por la que dije "en este caso" es porque only funciona porque $ AoA [0] ya
celebró una referencia de matriz. Si prueba eso en una variable indefinida, tomará una
excepción. Eso es porque la desreferencia implícita nunca autovivificará un indefinido
variable de la forma en que "@ {}" siempre lo hará:
my $ aref = undef;
push $ aref, qw (algunos valores más); # ¡INCORRECTO!
push @ $ aref, qw (algunos más); # OK
Si desea aprovechar este nuevo comportamiento de desreferenciación implícita, continúe:
hace que el código sea más fácil para la vista y la muñeca. Solo entienda que las versiones anteriores se ahogarán
en él durante la compilación. Siempre que haga uso de algo que solo funciona en algunos
dado el lanzamiento de Perl y posterior, pero no antes, debe colocar un lugar destacado
utilizar v5.14; # necesario para la eliminación implícita de las referencias de matriz por operaciones de matriz
directiva en la parte superior del archivo que lo necesita. De esa forma, cuando alguien intente ejecutar el
nuevo código en un antiguo perl, en lugar de obtener un error como
El tipo de arg 1 para insertar debe ser una matriz (no un elemento de matriz) en / tmp / a línea 8, cerca de "" betty ";"
La ejecución de / tmp / a se canceló debido a errores de compilación.
serán informados cortésmente de que
Se requiere Perl v5.14.0 - esto es solo v5.12.3, detenido en / tmp / a línea 1.
BEGIN falló: compilación cancelada en / tmp / a línea 1.
Acceda a y Impresión
Ahora es el momento de imprimir su estructura de datos. Cómo vas a hacer eso? Bueno, si
quieres solo uno de los elementos, es trivial:
imprimir $ AoA [0] [0];
Sin embargo, si desea imprimir todo, no puede decir
imprimir @AoA; # INCORRECTO
porque solo obtendrá referencias en la lista, y Perl nunca desreferenciará automáticamente
cosas para ti. En cambio, tienes que darte un vuelco o dos. Esto imprime todo
estructura, usando el estilo de concha por() construir para recorrer el conjunto exterior de
subíndices.
por $ aref (@AoA) {
decir "\ t [@ $ aref]";
}
Si desea realizar un seguimiento de los subíndices, puede hacer esto:
por $ i (0 .. $ # AoA) {
decir "\ t elt $ i es [@ {$ AoA [$ i]}],";
}
o tal vez incluso esto. Observe el bucle interior.
por $ i (0 .. $ # AoA) {
por $ j (0 .. $ # {$ AoA [$ i]}) {
decir "elt $ i $ j es $ AoA [$ i] [$ j]";
}
}
Como puede ver, se está volviendo un poco complicado. Por eso a veces es más fácil tomar una
temporal en su camino a través de:
por $ i (0 .. $ # AoA) {
$ aref = $ AoA [$ i];
por $ j (0 .. $ # {$ aref}) {
decir "elt $ i $ j es $ AoA [$ i] [$ j]";
}
}
Hmm ... eso sigue siendo un poco feo. Qué tal esto:
por $ i (0 .. $ # AoA) {
$ aref = $ AoA [$ i];
$ n = @ $ aref - 1;
por $ j (0 .. $ n) {
decir "elt $ i $ j es $ AoA [$ i] [$ j]";
}
}
Cuando se canse de escribir una impresión personalizada para sus estructuras de datos, puede mirar
los módulos Dumpvalue o Data :: Dumper estándar. El primero es lo que el depurador de Perl
utiliza, mientras que el último genera código Perl analizable. Por ejemplo:
utilizar v5.14; # usando el + prototipo, nuevo en v5.14
sub show (+) {
requiere valor de volcado;
estado $ hermosamente = nuevo valor de volcado ::
tick => q ("),
compactDump => 1, # comenta estas dos líneas
veryCompact => 1, # si quieres un volcado más grande
;
dumpValue $ hermosamente @_;
}
# Asignar una lista de referencias de matriz a una matriz.
mi @AoA = (
["fred", "barney"],
["george", "jane", "elroy"],
["homer", "marge", "bart"],
);
presione $ AoA [0], "wilma", "betty";
mostrar @AoA;
imprimirá:
0 0..3 "fred" "barney" "wilma" "betty"
1 0..2 "george" "jane" "elroy"
2 0..2 "homer" "marge" "bart"
Mientras que si comenta las dos líneas que dije que le gustaría, entonces se las muestra.
de esta manera en su lugar:
0 FORMACIÓN(0x8031d0)
0 "fred"
1 "barney"
2 "wilma"
3 "betty"
1 FORMACIÓN(0x803d40)
0 "jorge"
1 "jane"
2 "elroy"
2 FORMACIÓN(0x803e10)
0 "jonrón"
1 "marge"
2 "bart"
Rebanadas
Si desea obtener un segmento (parte de una fila) en una matriz multidimensional, va a
tengo que hacer un subíndice elegante. Eso es porque si bien tenemos un buen sinónimo de
elementos individuales a través de la flecha del puntero para desreferenciar, no existe tal conveniencia para
rodajas
A continuación, se explica cómo realizar una operación mediante un bucle. Asumiremos una variable @AoA como antes.
@parte = ();
$ x = 4;
para ($ y = 7; $ y <13; $ y ++) {
presione @part, $ AoA [$ x] [$ y];
}
Ese mismo bucle podría reemplazarse con una operación de corte:
@part = @ {$ AoA [4]} [7..12];
o espaciado un poco:
@part = @ {$ AoA [4]} [7..12];
Pero como bien puede imaginar, esto puede resultar bastante duro para el lector.
Ah, pero ¿y si quisieras un bidimensional rebanada, como tener $ x desde 4..8 y $ y
correr de 7 a 12? Hmm ... aquí está la forma sencilla:
@nuevoAoA = ();
para ($ iniciox = $ x = 4; $ x <= 8; $ x ++) {
para ($ inicial = $ y = 7; $ y <= 12; $ y ++) {
$ newAoA [$ x - $ startx] [$ y - $ starty] = $ AoA [$ x] [$ y];
}
}
Podemos reducir algunos de los bucles a través de cortes.
para ($ x = 4; $ x <= 8; $ x ++) {
empujar @newAoA, [@ {$ AoA [$ x]} [7..12]];
}
Si estuvieras en las transformaciones de Schwartzian, probablemente habrías seleccionado un mapa para eso.
@newAoA = mapa {[@ {$ AoA [$ _]} [7..12]]} 4 .. 8;
Aunque si su gerente lo acusó de buscar seguridad laboral (o inseguridad rápida) a través de
código inescrutable, sería difícil de discutir. :-) Si yo fuera tú, lo pondría en un
función:
@newAoA = splice_2D (\ @AoA, 4 => 8, 7 => 12);
sub empalme_2D {
my $ lrr = turno; # ref a la matriz de referencias de matriz!
mi ($ x_lo, $ x_hi,
$ y_lo, $ y_hi) = @_;
volver mapa {
[@ {$ lrr -> [$ _]} [$ y_lo .. $ y_hi]]
} $ x_lo .. $ x_hi;
}
Use perllol en línea usando los servicios de onworks.net