Listas. Manejo básico
Las listas son las colecciones nativas de datos más simples y flexibles con las que cuenta Python, lo que hace que sean usadas con mucha frecuencia.
Las listas son las colecciones nativas de datos más simples y flexibles con las que cuenta Python, lo que hace que sean usadas con mucha frecuencia.
Lista como iterable
Ya hemos tenido ocasión de comprobar la utilidad que tiene el uso de un array como iterable en la automatización de procedimientos cuando trabajamos con OOo Basic. Uno de esos iterables en Python son las listas, de ahí el interés por saber iterar por ellas.
De hecho la iteración se presenta en Python más sencilla y a la vez más variada en cuanto procedimiento; y también más potente. Trataremos en esta entrada sobre las diferentes formar de iterar por una lista... y algo más.
Partiendo de la estructura for como instrucción básica para la iteración, la forma más sencilla de iterar es tomar como referente el elemento y como iterable la lista. Así, dada una lista (vg. los curso de E. Primaria)...
cursos = ['P1','P2','P3','P4','P5','P6']
... podemos recorrer la lista del siguiente modo:
for curso in cursos:
print(curso)
Otra forma de iterar es obtener el número de elementos de la lista mediante la función len() y usar la variable asociada (o la misma expresión) como límite superior del recorrido a realizar (1):
n = len(cursos)
for i in range (n):
print(cursos[i])
En ocasiones nos puede venir bien recuperar a la vez el dato y el índice que, como elemento, ocupa en la lista. Para estos casos disponemos de un método específico:
for index, curso in enumerate (cursos):
print(index, curso)
Otra situación especial, que no podemos contemplar como específica en OOo Basic, aunque podemos simularla de otro modo, es cuando disponemos de dos o más listas y deseamos iterar por ambas, simultaneándolas:
cursos = ['P1','P2','P3','P4','P5','P6']
intervalos = ['2000/2001','2001/2002','2002/2003','2003/2004','2005/2006','2006/2007']
for curso, intervalo in zip(cursos, intervalos):
print(intervalo, curso)
Finalmente también podemos iterar secuencialmente (2) por dos o más listas. Para ello primero importamos el módulo itertools y después usamos el método itertools.chain(), como vemos en este ejemplo:
import itertools
for item in itertools.chain(cursos, intervalos):
print(item)
A partir de aquí ya podemos utilizar las listas para automatizar procedimiento al mismo nivel que hacemos en OOo Basic, sólo de con mayor facilidad y potencia.
NOTAS
Modificar el contenido de una lista
Trataremos en esta entrada cómo modificar los elementos que componen una lista mediante diferentes funciones y procedimientos completando lo visto en entradas anteriores, especialmente [en esta] cerrando una temática que lleva abierta desde hace tiempo.
Una vez definida una lista vacía (lista_1 = []) (1) tenemos dos funciones para añadir elementos:
Añadir elementos al final (append())
lista_1.append('Rosa')
Añadir elementos en una posición intermedia (insert(indice,elemento))
lista_1.insert(1,'Cecilia')
Observa que para añadir elementos en una posición determinada debemos indicar como primer parámetro el índice (o posición) que deseemos que ocupe el elemento.
Si lo que deseamos es añadir un conjunto de elementos a la lista, todos a la vez, usaremos la función (extend([]))
lista_1.extend(['Maria','Celia'])
En realidad lo que añadimos es una lista a la lista anterior, motivo por el cual situamos los elementos entre corchete. De no hacerlo obtendremos error o un resultado inesperado (2)
También contamos con funciones para borrar o eliminar elementos de la lista:
Eliminamos el elemento identificado de la lista mediante (remove())
lista_1.remove('Rosa')
El método (pop()) elimina por defecto el último elemento de la lista...
lista_1-pop()
... pero si le pasamos como parámetro un índice válido de la lista elimina el elemento que ocupe esa posición
lista_1.pop(2)
Pero el método más simple para borrar un elemento es usar la instrucción del
del lista_1[0]
NOTAS
lista1 = list([1,2,3,4])lista2 = list([5,6,7,8])print(lista1 + lista2) -> devuelve [1,2,3,4,5,6,7,8]
print(5 in lista1) devuelve Falseprint(1 in lista1) devuelve Falseprint(5 not in lista1) devuelve Trueprint(1 not in lista1) devuelve Trueprint(5 in tupla1) devuelve Falseprint(1 in tupla1) devuelve Falseprint(5 not in tupla1) devuelve Trueprint(1 not in tupla1) devuelve True
Los operadores relacionales permiten comparar dos listas entre sí, elemento a elemento y según criterios específicos en función del tipo de elemento. También devuelven True o False, según el resultado de la comparación. Veamos algunas comparaciones, tomando como referencia las listas y las tuplas creadas antes. Dada la multiplicidad de opciones me limitaré a unos pocos ejemplos, aunque los resultados se pueden hacer extensibles al resto de los operadores:
#Operadores relacionales con listas
print(lista1 == lista1) devuelve True
print(lista1 != lista2) Devuelve True
#Operadores relacionales con tuplas
print(tupla1 == tupla1) Devuelve True
print(tupla1 != tupla2) Devuelve True
#Operadores relacionales con listas y tuplas
print('Operadores relacionales con listas y tuplas')
print(lista1 == tupla1) Devuelve False por ser una lista y la otra tupla, aunque su contenido es el mismo (valores enteros 1,2,3,4 en ambos casos)
mi_lista_b = [['Lucía','Martínez Alonso','P4'],['Mario','Carcedo Suárez','P3'],['Carlota','Álvarez López','P2']]
Veamos mediante código distintas posibilidades de acceso al contenido de esta lista. Denominaré registro a cada una de las tres sublistas y dato a cada uno de los elementos de cada uno de los registros (dato -> nombre, dato -> apellidos, dato -> curso)
#Acceso a la lista completa
print(mi_lista_b)
#Captura del primer registro
reg1 = mi_lista_b[0]
#Acceso al primer registro de la lista
print(mi_lista_b[0])
#Acceso al primer registro que pasamos previamente a reg1
print(reg1)
#Acceso al primer dato (dato -> nombre) de cada uno de los registros de la lista
reg_nombres = [[mi_lista_b[0][0]], [mi_lista_b[1][0]],[mi_lista_b[2][0]]]
print(reg_nombres)
#Acceso al primer dato del nueva lista reg_nombres
print(reg_nombres[0])
#Otro modo de acceso (ahora reg_nombres_b es una lista de elementos imples
reg_nombres_b = [mi_lista_b[0][0], mi_lista_b[1][0],mi_lista_b[2][0]]
print(reg_nombres_b)
['Lucía', 'Martínez Alonso', 'P4']
Si lo que queremos es acceder al primer datos de la primera sublista, deberemos expresarlo como sigue: print([mi_lista_b[0][0]) (nos devuelve -> Lucia). Observa que empleamos una pareja de corchetes para identificar el registro (en este caso el primero [0]) y a continuación una segunda pareja para identificar el datos que deseamos (en este caso también el primero [0])
Haciendo extensible este procedimiento, podemos crear una lista de listas que contienen como único registro el nombre de cada alumno...
reg_nombres = [[mi_lista_b[0][0]], [mi_lista_b[1][0]],[mi_lista_b[2][0]]]
... o, como alternativa, una lista de elementos simples con el mismo contenido
reg_nombres_b = [mi_lista_b[0][0], mi_lista_b[1][0],mi_lista_b[2][0]]
La diferencia es sutil pero fundamental: en el primer caso delimitamos doblemente con corchetes cada elemento, en el segundo no. Con el primer procedimiento obtenemos una lista de listas simples (de un sólo elemento o dato cada una)...
[['Lucía'], ['Mario'], ['Carlota']]
... y con el segundo una lista simple de tres elementos (2)
['Lucía', 'Mario', 'Carlota']
Además de acceder a elementos concretos de la lista o de la tupla, también podemos hacerlo a un subconjunto de datos mediante el operador :. De este operador ya hablamos en [esta entrada], pero dejamos apartado su tratamiento para relacionarlo con los procedimientos de acceso al contenido, motivo por el que corresponde ahora tratarlo.
Este operador presenta una formulación básica lista/tupla[inicio:fin] en la que se indica la posibilidad de delimitar el inicio del subconjunto y su final (mejor dicho, el elemento previo a su final). Por ejemplo, para lista0 = [1,2,3,4,5,6,7,8,9], print(lista0[0:3]) nos devuelve [1,2,3], dado que se cuentan los elementos empezando por 0 y el elemento posición 3 (->4) es 4, por lo que el anterior (elemento 2 -> 3).
Ahora bien podemos omitir tanto el elemento inicio como el elemento fin. En el primer caso (vg. lista0[:3]) el resultado será el mismo que antes ([1,2,3]) ya que la ausencia del delimitador inicio implica partir del primer elemento de la lista (o de la tupla). Si omitimos el elemento final (vg lista0[2:]) implícitamente suponemos que deseamos ir desde el elemento inicio (posición 2 -> 3) hasta el final de la lista. En consecuencia, para lista0 -> [3,4,5,6,7,8,9].
Otra forma de acceder a segmentos del contenido de listas o tuplas es empleando índices negativos...
print(lista0[-5:-3]) -> devuelve [5,6]
print(tupla0[-2:]) -> Para tupla0 da igual contenido que lista0, esto es, devuelve (8,9)
... debido a que los valores negativos remiten al orden inverso en el acceso al contenido de listas y tuplas.
NOTAS
Uno de los tipos específicos de texto que tenemos que crear con cierta frecuencia son los listados, bien como documentos en si mismos, bien como elementos de un documento más amplio. Para hacerlo mediante teclado (que suele ser lo común) existen tres opciones básicas: crear la lista desde cero, copiar y pegar los ítem recurriendo a un documento externo que contiene la lista maestra o utilizar esa lista maestra como plantilla y, al contrario que en los casos anteriores, eliminar los ítem que no interesen. Aunque la tercera fórmula es el modo de trabajo que más se acerca al objetivo de la automatización, todas ellas, en realidad, están muy lejos que acercarse a este objetivo. Usar macros y script (OOo Basic) es la única forma en que realmente se facilitar la tarea.
En cualquier caso, y para lo que ahora nos importa, disponer de procedimientos de generación informatizada de listados nos va a ayudar a simplificar el trabajo, aunque requiera uno previo.
No me voy a detener demasiado en el aspecto formal de la creación de un listado, que podemos resolver mediante el uso de tablas o mediante la activación de las marcas del ítem de lista (vg. un número índice o una bolita) por medio de una macro. Pero tampoco quiere dejar de explicar cómo hacerlo, así que dedicaremos el inicio de esta entrada a explicar esta forma de trabajo mediante macros simples y script.
Como sabemos, las listas son de dos tipos genéricos: alfanuméricas y gráficas. Las dos macros simples que las generan son las siguientes:
Alfanumérica:
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "On"
args1(0).Value = true
dispatcher.executeDispatch(document, ".uno:DefaultNumbering", "", 0, args1())
Gráfica (en este caso de bolita)
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "On"
args1(0).Value = Valor
dispatcher.executeDispatch(document, ".uno:DefaultBullet", "", 0, args1())
Ambas trabajan con argumentos booleanos (arg().Value), así que la conversión de estas macros simples en subrutinas para ser empleadas desde un script, supone implementar un argumento (variable) de tipo Boolean: sub ListaSimple (Valor As Boolean) que deberemos incluir en la llamada a la subrutina como en este ejemplo: ListaSimple(True). Cuando queramos finalizar el listado, deberemos llamar de nuevo a la subrutina y cambiar el argumento a False.
Además de este código, también necesitamos el código (macro o script) de escritura y el salto de línea al finalizar el ítem...
dispatcher.executeDispatch(document, ".uno:InsertPara", "", 0, Array())
Podemos anidar listas (e ítem) mediante el uso de tabulador, generando un incremento del sangrado que facilita la estructuración de la lista en ítem principal e ítem secundario. Para ellos haremos uso de la misma macro-subrutina de escritura, pasando como argumento el carácter especial Chr$(9). A continuación te muestro el script que nos permite generar una lista (los inicios de la misma) que contiene otra anidada. Hacerla más amplia y funcional es cosa de escribir más líneas de código:
Sub CrearLista
VarSis
ListaSimple(True)
Escribir("Listado de alumnos con NEE")
SaltarLinea
ListaSimple(False)
Escribir(Chr$(9))
ListaSimpleNum(True)
Escribir("Jaime Ortega López")
End Sub
... y este es el resultado. Simple por haberme ahorrado esfuerzos, pero suficiente para explicar lo que me interesa.
Sub Semana
VarSisDim DiasSemana(6) As StringDim i As Integer
DiasSemana(0) = "Lunes"DiasSemana(1) = "Martes"DiasSemana(2) = "Miércoles"DiasSemana(3) = "Jueves"DiasSemana(4) = "Viernes"DiasSemana(5) = "Sábado"DiasSemana(6) = "Domingo"
ListaSimple(True)Escribir("Días de la semana")SaltarLineaListaSimple(False)Escribir(Chr$(9))ListaSimpleNum(True)
For i = LBound(DiasSemana()) To UBound(DiasSemana())Escribir(DiasSemana(i))If i < UBound(DiasSemana()) ThenSaltarLineaEnd IfNext
End Sub
Como puedes observar, este script se divide en cuatro partes:
Muestro a continuación el resultado. No parece gran cosa, pero que supone la escritura automática de una lista:
Nos falta dar un paso más que básicamente consiste en dar la posibilidad de automatizar la escritura de una lista resultante de la selección de ítem de otra lista. Viene a ser el equivalente a trabajar sobre un documento-base que contiene a lista completa de la que vamos borrando los elementos que no nos interesan. De este modo conseguimos generar listas personalizadas, con todos los posibles usos prácticos que podemos intuir (4)
Este es el script. Por simplicidad sustituyo la escritura en el documento por el mero visionado de los elementos de la lista mediante MsgBox, pero el principio de funcionamiento del script no supone una variación sustancial. Esta simplificación permite que nos centremos en lo fundamental del funcionamiento del script.
Sub MatrizSemana
Dim DiasSemana(6) As String
Dim MisDias () As String
Dim Dia As Integer
Dim i As Integer, b As Integer
DiasSemana(0) = "Lunes"
DiasSemana(1) = "Martes"
DiasSemana(2) = "Miércoles"
DiasSemana(3) = "Jueves"
DiasSemana(4) = "Viernes"
DiasSemana(5) = "Sabado"
DiasSemana(6) = "Domingo"
b = 0
For i = LBound(DiasSemana()) To UBound(DiasSemana())
Dia = MsgBox (DiasSemana(i),4,"MIS DIAS")
If Dia = 6 Then
ReDim Preserve MisDias(b)
MisDias(b) = DiasSemana(i)
b=b+1
End If
Next
MsgBox "Número de días seleccionados: " & CStr(UBound(MisDias()) + 1)
For i = LBound(MisDias()) To UBound(MisDias())
MsgBox MisDias(i)
Next
End Sub
Dia = MsgBox (DiasSemana(i),4,"MIS DIAS")
NOTAS.