Mostrando entradas con la etiqueta Colecciones de datos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Colecciones de datos. Mostrar todas las entradas

viernes, 16 de mayo de 2025

Python. Lenguaje.

Listas y tuplas.
Operadores


Los operadores son, [según sabemos], componentes de todo lenguaje de programación que permiten manipular los datos referenciados en las variables de diferentes maneras, según el tipo de operador y de datos de que se trate. También las colecciones de datos admiten la acción de operadores y listas y tuplas comparten los mismos.



Los operadores disponibles en listas y tuplas son los siguientes:
  • :, que permite obtener segmentos del contenido de ambas colecciones.
  • + y *, que permiten realizar las operaciones sobre listas y tuplas. Veremos cuáles.
  • in / not in, que permiten verificar la presencia / no presencia de determinado dato dentro del conjunto.
  • Y los operadores relacionales <, <=, >, >=, == y !=, cuyas funciones describiremos en su momento.
Aunque figure en primer lugar, no trataré el operador : en esta entrada, dada la relación que mantiene con el acceso a los datos. Por este motivo desplazo su análisis a la [entrada correspondiente]

Inicio este análisis con los operadores + y , los cuales cumplen funciones específicas con listas y tuplas, diferentes de las que permiten hacer con variables. 
  • El operador + permite la unión o concatenación de los elementos de varias listas , como cabe suponer por lo que sabemos de los operaciones aritméticos, nos permiten realizar operaciones de suma y multiplicación con listas y tuplas.
lista1 = list([1,2,3,4])
lista2 = list([5,6,7,8])
print(lista1 + lista2) -> devuelve [1,2,3,4,5,6,7,8]

  • Este mismo operador, aplicado a tuplas funciona exactamente igual, aunque lógicamente devuelve una tupla ((1,2,3,4,5,6,7,8))
  • La operación * tiene como efecto la repetición de la lista o la tupla sujeta a tal operación, siendo indiferente que el operador se sitúa antes o después de la lista o tupla. Así que print(3 * lista1) devuelve [1,2,3,4,1,2,3,4,1,2,3,4] y print(tupla1 * 2) devuelve (1,2,3,4,1,2,3,4). En ambos casos el número debe ser entero (ni 3.1 ni 2.4 se admiten como "multiplicadores")
  • Ambos operadores tienen el mismo efecto con independencia de la naturaleza de los elementos de la lista o de la tupla.
  • En ambos casos no está permitido el trabajo con listas y tuplas simultáneamente. No es posible ni lista + tupla, ni tupla * lista, ni ninguna otra combinación o permutación de elementos.
Los operadores in / not in permiten identificar si un datos forma parte o no de una lista o de una tupla. in y not in devuelven el booleano True o False según el resultado de la operación. Ejemplos para lista1 y tupla1 anteriores:

print(5 in lista1) devuelve False
print(1 in lista1) devuelve False

print(5 not in lista1) devuelve True
print(1 not in lista1) devuelve True

print(5 in tupla1) devuelve False
print(1 in tupla1) devuelve False

print(5 not in tupla1) devuelve True
print(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)

jueves, 15 de mayo de 2025

Python. Lenguaje.

Listas y tuplas
Creación automática de contenido


Aunque la forma más frecuente de crear colecciones de datos es introducirlos directamente mediante teclado o acceder a documentos en los que estos se encuentren disponibles, por diferentes motivos, en ocasiones es necesario crear colecciones de datos numéricos más o menos amplias cuyos elementos mantienen entre sí una relación, lo que hace que sea posible automatizar ese proceso. Para estos casos es muy útil conocer procedimientos de creación automática de colecciones de datos. Y existen... tanto para listas y como para tuplas.


El primer procedimiento para crear listas (y tuplas) automáticamente es el que utiliza la función range(). Esta función precisa tres parámetros: el valor de inicio, el valor final y el incremento. Un ejemplo: range(2,12,2) nos permite crear una colección de datos que inicia en el número 2 y finaliza en el 10 (el 12 no está incluido), incrementándose el valor inicial de 2 en 2 (2 - 4 - 6...).

Utilizamos el constructor de listas y creamos automáticamente una que cumple esos criterios. Si la lista es pequeña podemos hacerlo manualmente, pero si contiene muchos elementos es mucho más funcional usar la función range() que acabo de explicar: 
  • lista_1 = list(range(2,100,2)) crea una lista con todos los números pares comprendidos entre 2 y 100 (100 no incluido).
  • tupla_1 = tuple(range(2,100,2)) tiene el mismo efecto práctico, aunque en este caso se trata de una tupla, con todo lo que esto implica respecto a inmutabilidad.
Existen otros procedimientos que además de permitirnos crear colecciones de datos numéricos más complejas, también es necesario conocer para entender de qué se trata si nos encontramos con script que utilicen estas expresiones. Me estoy refiriendo a la creación de listas o tuplas que utilizan operadores, bucles y condicionales como parte de las expresiones que utilizan para crear la lista o tupla. Veamos algunos ejemplos: 
  • La lista_3 = [x * 2 for x in lista_1] es una lista de valores numéricos que utiliza la lista_1 (recuerda: números pares comprendidos entre 2 y 98) multiplicando por 2 cada uno de ellos. Mediante for x in lista_1 recorre esa lista.
  • La tupla_2 =tuple([x * 2 for x in tupla_1]) hace lo mismos pero creando una tupla y usando una tupla como base. Observa que ahora necesitamos usar el constructor de tuplas (antes no el listas) y usamos una combinación de ([]).
  • La lista_4 = [x**2 for x in lista_1 if x > 8] hace los mismo que lista_2, pero ahora añadimos como condición para la creación de la colección de datos que el valor original de lista_1 sea superior a 8 (if x > 8)
  • Finalmente, en lista_6 = [x * 3 for x in range(2,32,2) if x >10] utilizamos directamente la función range() para crear automáticamente la colección de datos de base (for x in range(2,32,2)) y mantenemos una condición: que los valores resultantes sean superiores a 10 (if x >10)
Y digo finalmente para no prolongar esta casuística más de lo necesario, porque aun caben otras combinaciones, incluyendo la de listas y tuplas y el uso de doble bucle en función de una doble variable (lista_5 = [x + y for x in lista_1 for y in lista_2]

Documento. En [este enlace] te dejo acceso a un script con ejemplos, incluidos los explicados en esta entrada.


martes, 13 de mayo de 2025

Python. Lenguaje.


Listas y tuplas
.

Acceso al contenido



Aunque listas y tuplas son colecciones de datos diferentes, ya dijimos que comparten muchas características y comportamientos; entre estos últimos están su contenido y el modo en que podemos acceder a él. 

El acceso a los elementos de las listas y las tuplas es un procedimiento de uso muy frecuente y de mucha utilidad práctica, por lo que interesa conocer cómo realizarlo. 

Ya sabemos cómo es el procedimiento básico por haberlo visto al hablar de ambas colecciones de datos (v.g. print(mi_tupla_a[0] nos devuelve en pantalla el primer elemento de la tupla), pero esto nos sirve cuando la tupla o la lista contienen elementos simples (vg mi_lista_a = [12,23,43,56]), pero, ¿ cómo accedemos a los elementos complejos, a las listas o tuplas anidados dentro de la lista o tupla principal?.

Un ejemplo de ello podría ser el siguiente: una lista que contiene "registros" que se comportan, a su vez como listas (1):

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)

En este script estamos jugando con diferentes formas de acceder al contenidos de una lista compleja (lista de listas). Podemos diferenciar el modo de acceder al conjunto de la lista (print(mi_lista_b)) y a su primer elemento (print(mi_lista_b[0])). En el primer caso nos devuelve todos los registros de la lista (la lista con sus sublistas...

[['Lucía', 'Martínez Alonso', 'P4'], ['Mario', 'Carcedo Suárez', 'P3'], ['Carlota', 'Álvarez López', 'P2']]

... y en el segundo sólo el primer registro (la primera sublista)

['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

(1) El mismo ejemplo podríamos plantear mediante una tupla de tuplas, una lista de tuplas o una tupla de listas.
(2) Podríamos hacer exactamente lo mismo con una tupla y obtendríamos los mismos resultados. 

jueves, 26 de diciembre de 2024

Lenguajes. R.

Vectorización de una matriz

Al igual que sucede con los vectores, también podemos vectorizar las operaciones matemáticas a los componentes de una matriz: al aplicar esa operación a la matriz, se aplica a cada uno de sus elementos, con independencia de la posición fila-columna que ocupen.



Además la vectorización también se aplica a los operadores relacionales, y como en el caso de los vectores, se trata de una operación que no altera la composición original de la matriz, por lo que si nos interesa conservar el resultado de la vectorización para operar después con él, deberemos asociarlo a una nueva matriz, resultante de la vectorización de la primera. 

Veamos este procedimiento sobre un ejemplo, partiendo de dos vectores...
  • alumnos <- c(24,22,20,19,21,25)
  • mataprob <- c(67,72,84,53,82,79)
...convertidos en matriz (cole <- rbind(alumnos,mataprob)que vectorizamos mediante un operador lógico (cole < 30), operación que asignamos a una nueva matriz (cole2 <-cole < 30). Observa el resultado de visualizar ambas matrices (cole y cole2) en la consola:


Como ves, mientras que cole conserva los valores iniciales, cole2 contiene el resultado de la vectorización: gracias a esta operación disponemos de una nueva matriz que recoge el resultado de aplicarla a cada uno de los datos de la matriz original.

Pero, ¿qué pasa si realizamos una vectorización (por ejemplo, aplicando ese mismo operador relacional) a una matriz que contiene datos alfanuméricos?. Si te fijaste en la imagen de matrices de la [entrada anterior], matriz resultante de la inclusión de tres vectores, el primero de los cuales estaba compuesto de datos alfanuméricos, todos sus datos habían sido transformados en datos alfanuméricos (de ahí que aparezcan entrecomillados).

Pues bien, si realizamos esta vectorización, el resultado es cuanto menos sorprendente, ya que devuelve FALSE para los datos alfanuméricos (identificador de curso) y TRUE o FALSE, según corresponde, en los numéricos primitivos  convertidos en alfanuméricos. Pero si la vectorización consiste en realizar una operación matemática (vg. cole2 <-cole * 30) el resultado es un mensaje de error, esperable por otra parte, ya que no puede realizar esa operación con los datos no-numéricos. La diferencia entre ambas operaciones es que no se ejecuta la vectorización con ninguno de los datos dado que ninguno es ya numérico.





Lenguajes. R.

Vectores. Definición.

Un vector es la colección de datos más sencilla con la que trabaja R. Es unidimensional y contiene datos del mismo tipo, aunque puede constar de metadados que describen los datos que contiene (1).


R es un lenguaje vectorizado, lo que quiere decir que se puede considerar al vector como un tipo básico de datos en este lenguaje; algo que es coherente con el objetivo para el que fue pensado como lenguaje. De hecho, y a la inversa, se puede considerar cualquier variable como un vector de un único dato (2)

Para crear un vector usaremos la función c() (concatenar) (3) y el operador de asignación, por ejemplo:
  • num <- c(1,3,5,7)
  • pal <- c("mesa","silla","cama")
Si lo que necesitamos es crear un vector de números consecutivos podemos hacerlo de este modo: num <- 1:10, que crea un vector con los números 1...10 de forma directa (4)

En R es muy sencillo añadir elementos a un sector ya creado (5), siendo suficiente con reutilizar el vector previamente creado de forma recursiva:
  • num <- c(1,3,5,7)
  • num <- c(num,9)
En este caso añadimos al final del vector num un nuevo dato (9), pero podríamos añadirlo al inicio o añadir más de un dato usando el mismo procedimiento, pero variando la posición o la cantidad de dados. Del mismo modo, podemos crear vectores de vectores (numc <- c(numa,numb)), operación que realizaremos con frecuencia (6).

Al añadir un dato a un vector o al crear un vector de vectores, se puede dar el caso que el tipo de dato no sea el mismos, lo que aparentemente es una contradicción con el criterio de que un vector contiene datos del mismo tipo. Este problema se resuelve en R de forma automática mediante el mecanismo de coerción (7)

Para ver el contenido de un vector es suficiente con escribir su nombre y pulsar intro; y si queremos acceder a un elemento en concreto escribiremos el nombre del vector y su id entre corchetes (num[1]) y pulsamos intro (8). El mismo resultado obtendremos si utilizamos la función print(), pasando como argumento el nombre del vector (print(num)), en el primer caso, y la expresión num[1] en el segundo.

El acceso a un elemento del vector nos permite generar variables a partir del vector por el simple procedimiento de asignación del componente a la variable (num2 <- num[1]) (9)

Si queremos eliminar un elemento (o varios) de un vector (10), o crear un subvector a partir del original menos determinado/s elemento/s, es suficiente con añadir el signo - al índice de posición del elemento (num[-1]) o a la función c() (num[-c(1)]). Esta sustracción sólo elimina el elemento en el momento en que se ejecuta, pero no altera la composición original del vector, así que si lo que necesitamos es un nuevo vector que no cuente con esos elementos, deberemos asociar la operación anterior a la creación de dicho subvector (numB <- num[-1]).


NOTAS

(1) El tema de los metadados supera los objetivos de este blog, por lo que no será tratado. No obstante es una cuestión de un alto nivel de complejidad, por lo que es frecuente trabajar con vectores sin hacer referencia a sus metadatos.
(2) Si, por ejemplo, utilizamos la función is.vector(3), nos devolverá TRUE, y si solicitamos información sobre su longitud (length(3)) nos devolverá 1. Esto implica que R está tratando el dato 3 como vector. Lo mismo sucederá si asociamos este dato a una variable (num <- 3) y la usamos como argumento de ambas funciones.
(3) También podemos usar las funciones rep() y seq(), que permiten crear patrones.
(4) Esta formulación admite también números decimales y negativos, así como orden inverso.
(5) Lo que contrasta con la complejidad que presenta esta operación en OOo Basic y ejemplifica de nuevo la orientación de R al análisis de datos.
(6) En el supuesto de que numa <- c(1,2) y numb <- c(3,4), numc estaría formado por 1,2,3,4
(7) Conversión implícita de un tipo de dato a otro más flexible. Por ejemplo, si añadimos "once" al vector num (num <- c(num,"once")), todos los datos se convierten a tipo character. De la coerción ya hablamos [en esta entrada]
(8) La identificación de los componentes de los vectores no empiezan en 0, como sí ocurre en otros lenguajes, así que num[1] no devuelve el primer dato que contiene el vector.
(9) De hecho, una variable puede ser considerada como un vector de un único dato.
(10) Por lo que se precisa más adelante, es posible que en vez de decir "eliminar", debería decirse "visualizar el vector sin determinados elementos", ya que no se produce tal eliminación de datos del vector original.

lunes, 28 de octubre de 2024

Lenguajes. Python.

Diccionarios


El último tipo de colección de datos en Python es el diccionario, estructura cuyos elementos o componentes son pares llave/valor que denominamos entrada.


La llave puede ser cualquier elemento hashable, esto es, un objeto cuyo valor no cambia a lo largo de toda la ejecución del programa, siendo un hash el valor que identifica dichos objetos. Además, la llave no puede estar duplicada. El valor puede ser de cualquier tipo y puede estar repetido. Esta estructura del diccionario nos permite un rápido acceso a los datos que contiene.

La sintaxis del diccionario es la siguiente: al igual que los conjuntos, {} para delimitar su inicio y fin, entradas (pares llave/valor) separadas por comas y elemento llave-valor separados por dos puntos. 

  • Podemos declarar un diccionario directamente:

alumnos={"1º":"Juan", "2º":"Luis", "3º":"Melisa"}

  • O bien mediante el constructor de clase dict

alumnos = dict() -> Diccionario vacío
alumnos= dict(Uno="Juan", Dos="Luis", Tercero="Melisa") -> los números no son identificadores válidos, por lo que no pueden usarse como claves. Por este motivo, esta fórmula es poco empleada.

Al contario que los conjuntos, sí es posible acceder a un elemento concreto de un diccionario. Para ello utilizaremos la referencia llave, de forma similar a cómo hacíamos con listas y tuplas. Por ejemplo, para acceder al elemento 2, solicitaremos...

print(alumnos["2º"]) -> Devuelve Luis.

En este caso, tal y como definimos el contenido del diccionario, no podemos solicitar alumnos[1], ya que 1 no es la llave, sino 2º. Ahí radica una de  las diferencias entre diccionarios y listas/tuplas. Incluso aunque nuestro diccionario se configure como alumnos={1:"Juan", 2:"Luis", 3:"Melisa"}, si solicitamos el alumno situado como primera entrada deberemos hacerlo utilizando la llave de esa entrada (print(alumnos[1])), no su índice (print(alumnos[0])), orden que nos dará error.

También es posible añadir un nuevo elemento a un diccionario existente mediante el uso de la siguiente expresión: NombreDiccionario[llave]=valor. Por ejemplo, si deseamos añadir un cuarto elemento a nuestro diccionario alumnos diremos...

alumnos["4º"]="Carmela"

... por lo que si solicitamos ver el contenido de alumnos (print(alumnos)) obtendremos {1: 'Juan', 2: 'Luis', 3: 'Melisa', '4º': 'Carmela'}.

Igual que en lo relativo a las variables y al resto de las colecciones de datos, aun son muchas las cosas por aprender respecto a los diccionarios, y las iremos viendo en entradas sucesivas, pero por el momento considero que es suficiente como presentación y primer acercamiento a los diccionarios y, por extensión, a las colecciones de datos, por lo que cierro aquí, provisionalmente, este conjunto de entradas dirigidas a su presentación y primer análisis.

Lenguajes. Python.

Colecciones de datos. Tipología


Además de con datos individuales (variables) también podemos trabajar con  colecciones de datos, lo que nos permite simplificar y acortar el código, mejorando la eficiencia del algoritmo. En Python disponemos de varios agrupamientos de datos. En esta entrada realizaremos un breve introducción al tema.




En Python podemos usar con propiedad el término "colecciones" de datos, así, en plural, ya que contamos con cuatro tipos diferentes de colecciones: listastuplasconjuntos y diccionarios

Una lista es una colección o conjunto ordenado de datos que puede contener elementos de diferente tipo. Es la forma más simple de agrupamiento y se identifica por el uso de corchetes como delimitador: lista1 = ["ordenador","teclado"]

Una tupla es un conjunto de datos de diferente tipo. En ella los datos están ordenados y son inmutables, características estas que la diferencian de la lista: una tupla no se puede modificar una vez creada. La tupla queda delimitada por paréntesis:: tupla1 = ("ordenador",123,"teclado")

Mientras que en listas y tuplas identificamos sus elementos mediante un índice, en los conjuntos los elementos no se asocian a un orden, por lo que no emplean índices para localizar en ellos un elemento determinado. También frente a listas y tuplas, en los conjuntos no se pueden repetir contenidos (no puede haber dos elementos iguales), lo que nos acerca a la idea de conjunto matemático. Los conjunto se identifican por el uso de llaves como delimitadores: conjunto1 {"ordenador",1,"teclado"}

Finalmente, un diccionario es una colección de datos asociados en parejas, compuestas por una clave y un valor. Las claves no pueden repetirse. En Python los diccionarios se identifican, al igual que los conjuntos, por el uso de llaves como delimitadores, pero se diferencian por el uso de claves (llave) se asocian al valor mediante el separador "dos puntos" (:): diccionario1 = {1:"ordenador", 2:1, 3:"teclado"}

Con los visto hasta ahora nos podemos hacer una idea de la diversidad tipológica de las colecciones en Python. Esto supone cierta complejidad, pero también versatilidad en la definición y en el manejo de las colecciones de datos

En entradas posteriores desarrollaremos cada una de estas colecciones.

jueves, 13 de junio de 2024

Lenguajes. Python.

Listas.

Manejo básico

Dado que las listas son las colecciones de datos más simples con que cuenta Python, es necesario dedicar una entrada a aprender a trabajar con ellas.


Como dije [en su presentación], las colecciones de datos nos permiten almacenar un conjunto de datos asociados a una única referencia, mientras que con variable podemos acceder a un dato concreto. Python cuenta con cuatro tipos de colecciones de datos, siendo la lista la más simple y posiblemente también la más flexible de todas ellas.

Una lista es un conjunto ordenado de datos de diferente tipo (caracteres, cadenas, enteros, reales, booleanos) que pueden estar repetidos. Estas características, junto con las operaciones permitidas sobre ella, la convierten en un recurso muy flexible para el almacenamiento de datos.

La forma de declarar una lista es tan simple como se muestra en el ejemplo siguiente (1):

list_DiasSem = ["lunes","martes","miércoles","jueves","viernes"]

  • Se declara y asigna contenido de la misma forma y con el mismo operador que una variable, unificando ambos procesos en una única sentencia.
  • El identificador de la lista ([]) es su delimitador.
  • Los elementos de la lista se separan mediante comas.
  • Aunque en ésta todos los elementos son del mismo tipo, pueden ser de diferentes tipo.
  • Aunque podemos escribir la lista sin más, para poder acceder a ella o a alguno de sus elementos, es necesario asignarla a una variable (list_DiasSem)
  • Las listas pueden contener 0 elementos o todos los que deseemos.
Es importante entender que cada elemento de la lista ocupa una posición dentro de ella y que esta posición o índice es el que nos permite acceder a su contenido; de forma similar a cómo accedemos al contenido de una variable, pero respetando su sintaxis. Si para acceder al contenido de una variable únicamente tenemos que referenciarla, para acceder a un elemento determinado de una lista, debemos hacerlo especificando su índice. Si no indicamos ese índice se supone que estamos accediendo a toda la lista:
 
vPalabra = "casa"
lstPalabras = ["casa","mesa","armario"]
print(vPalabra) -> devuelve casa
print(lstPalabras[0]) -> devuelve casa
print(lstPalabras) -> devuelve ['casa','mesa','armario']

  • Si la lista lstPalabras estuviera vacía, print(lstPalabras[0]) provocaría un error (no hay elemento lstPalabras[0]), no así print(lstPalabras) -> devuelve [].
Podemos conocer el número de elementos de una lista mediante la función len(), cuyo resultado (return) podemos informar directamente mediante print(), o asignarla a una variable para su posterior uso. Por ejemplo, en list_DiasSem:

print(len(lis_DiasSem))                    -> Devuelve 5
vNumDiasSem=len(lis_DiasSem)
print(vNumDiasSemana)                  -> Devuelve 5

Una lista es modificable: podemos cambiar su contenido, añadir elementos o borrarlos, todo ello de forma muy simple:
  • Para cambiar un elemento, únicamente tenemos de reasignarle nuevo contenido haciendo uso de su índice; por ejemplo, siendo la lista...
vlstPalabras = ["casa","mesa","armario"]

 ... si queremos cambiar vlstPalabras[0] "casa" por "cama" diremos...

vlstPalabras[0] = "cama"

  • Para añadir un nuevo elemento a una lista podemos utilizar la siguiente expresión (el nuevo elemento se añade al final de la lista) (2):

 lstPalabras = lstPalabras + ["mesita"]

  • Para borrar un elemento de la lista usaremos la instrucción del de siguiente modo:

del lstPalabras[2] -> Borra el elemento "armario" que ocupa la tercera posición. 

Podemos trabajar con varias listas, por ejemplo dos, y unirlas en una tercera. Supongamos dos listas:

lstMuebles1=["mesa","silla","taburete"]
lstMuebles2=["sofá","armario","mesita"]

... la unión de ambas mediante la instrucción...

lstMuebles= lstMuebles1 + lstMuebles2

... nos da como resultado... 

print(lstMuebles) -> Devuelve ['mesa', 'silla', 'taburete', 'sofá', 'armario', 'mesita']

Además de unir dos listas en una tercera, también podemos considerar otras opciones, ya que una lista puede estar formada por una serie de elementos/datos (lista simple), pero también por una combinación de elementos y listas o por una colección de listas. La primera formulación ya la conocemos, tanto en su presentación más sencilla, como resultado de la unión o suma de dos listas; veremos a continuación las otras dos.

  • Lista resultante de la unión de una lista con otra mediante inclusión. Sea la lista inicial lstMuebles1=["mesa","armario"] y queremos modificarla para que esté conformada por la estructura de contenidos Muebles + Muebles de asiento; para ello creamos una segunda lista con muebles de asiento (lstAsientos=["silla","taburete","sillón","tresillo"]) y la incorporamos como elementos de la lista original:

lstMuebles=["mesa","armario",lstAsientos]

... obteniendo como resultado

print(lstMuebles) -> Devuelve ['mesa', 'armario', ['silla', 'taburete', 'sillón', 'tresillo']]

Obsérvese que lo que alteramos es la estructura de la primera lista, no unimos ambas, de ahí que los elementos de la segunda lista (que ocupa como elemento de la primera la posición 3 (lstMuebles[2]), aparecen delimitados mediante []. Esto es importante entenderlo, ya que el acceso a los contenidos de esta lista anidada se rigen por su doble posicionamiento: como elementos [2] de la lista principal y como elementos [x] de la lista secundaria. Así, si solicitamos el contenido de la posición [2], obtenemos...

 print(lstMuebles[2]) -> Devuelve ['silla', 'taburete', 'sillón', 'tresillo']

... por lo que si lo que deseamos es obtener el contenido de la posición 2 de la lista anidada (taburete), deberemos indicarlo con dos índices: el primero como elemento de la lista principal y el segundo de la lista anidada:

print(lstMuebles[2][1]) -> Ahora sí devuelve taburete

  • Un procedimiento similar se sigue para construir una lista formada por listas (lista de listas). Por ejemplo, supongamos que tenemos un conjunto de listas cuyos elementos representan subconjuntos de un conjunto principal y queremos representar esa pertenencia transformado el conjunto principal en una lista de listas, cuyos elementos son esos subconjuntos. 

lstFrutas=["pera","manzana","plátano"]
lstLegumbres=["garbanzo","lenteja","haba"]
lstHortalizas=["zanahoria","tomate","pimiento"]
lstVegetales=[lstFrutas,lstLegumbres,lstHortalizas]
print(lstVegetales) -> Devuelve [['pera', 'manzana', 'plátano'], ['garbanzo', 'lenteja', 'haba'], ['zanahoria', 'tomate', 'pimiento']]

El acceso a un elemento cualquiera de cualquiera de estas tres listas sigue el procedimiento explicado antes. Por ejemplo, para acceder al elemento 2  ([1]) de la lista 3 ([2]), se realiza con las siguiente instrucción:

 print(lstVegetales[2][1]) -> Devuelve tomate

El uso de bucles es una estrategia muy frecuente para recorrer los elementos de una lista y permite desarrollar procesos muy interesantes en la construcción de algoritmos. Esto es debido a la posibilidad de combinar el uso de las variables contador en combinación con los índices de las listas. Veamos un ejemplo sencillo: 

Supongamos una lista que contiene los nombres de los alumnos, una segunda que contiene sus apellidos y una tercera que contiene las calificaciones en una prueba.

lstNombre=["Julián","Pedro","Matilde", "Ana"]
lstApellidos=["Alonso Pérez","González López","Ramírez De Luis","Ordóñez Núñez"]
lstNotas=[8,9,7,4]

for i in range(4):
    print(lstNombre[i])
    print(lstApellidos[i])
    print(lstNotas[i])

Devuelve
Julián
Alonso Pérez
8
Pedro
González López
9
Matilde
Ramírez De Luis
7
Ana
Ordóñez Núñez
4

Pero en Python también podemos trabajar con el bucle for directamente sobre una lista, lo que simplifica enormemente la formulación de estas estructuras. Un ejemplo sobre una de las listas anteriores. Para ello es suficiente con emplear la expresión for item in NombreLista

lstNombre=["Julián","Pedro","Matilde", "Ana"]
for item in lstNombre:
    print(item,end=" ") -> Devuelve sucesivamente Julián  Pedro  Matilde  Ana

Una expresión similar a la anterior es la que usaremos para saber si un dato concreto forma parte de una lista. Sobre la lista anterior (lstNombre=["Julián","Pedro","Matilde", "Ana"]), para saber si el Carlos forma parte de la lista formularemos la siguiente instrucción: "Carlos " in lstNombre. Esta expresión devuelve un booleano (en este caso False, ya que Carlos no forma parte de lstNombre).

Podemos asociar esta búsqueda a un condicional y en función del resultado generar una bifurcación del algoritmo o, más sencillo, añadimos el elemento a la lista de nombres. Para ello primero deberemos asignar el resultado de "Carlos " in lstNombre a una variable:

vBoolA = "Carlos" in lstNombre

if vBoolA==False:
    lstNombre=lstNombre+["Carlos"]

print(lstNombre) -> Devuelve ['Julián', 'Pedro', 'Matilde', 'Ana', 'Carlos']

Mucho es aun lo que falta por aprender sobre las listas y su manejo, pero con lo visto ya hemos aprendido lo suficiente para incluirlas en nuestros ejercicios y proyectos (3).


NOTAS

(1) También podemos declarar una lista vacía (list_DiasSem = []) e ir llenándola de contenido según necesitemos. Esto puede ser de utilidad cuando desconozcamos de antemano el contenido de la lista. Para añadir elementos a una lista se usa la función append() (lista_DiasSem.append('Lunes'))
(2) Como sabes por 1, también puedes emplear la función append(). Más aun, es ésta la forma habitual de hacerlo.
(3) Entre otras fuentes de información, [esta referencia] es de mucho interés para saber más sobre las listas.

Lenguajes. Python.

Colecciones de datos. Conjuntos

El tercer tipo de colección de datos disponible en Python es el conjunto.

Un conjunto se diferencia de lista y tupla en dos características: no dispone de índice, por lo que no se puede acceder a su contenido mediante referencia a índice o valor de posición, y no admite elementos repetidos, lo que le asemeja al concepto matemático de conjunto.


Se recomienda utilizar conjunto en lugar de listas o tuplas cuando el volumen de datos que contiene la colección es muy elevada, ya que los conjuntos son mucho más eficientes: el acceso a la colección es en Python mucho más rápida en conjuntos que en listas o tuplas.

La sintaxis básica de un conjunto es su delimitación mediante llaves ({}), lo que permite crearlos directamente, asociados a una variable, mediante la siguiente instrucción (como ejemplo):

a = {1,3.4,"Casa"}

Al pedir la devolución de un conjunto tenemos que saber que el orden de devolución no es necesariamente el orden en que introdujimos los datos, ya que Python procede a ordenarlos según criterios propios. Por ejemplo, el conjunto {1,7,21,2} es devuelto como {1,2,21,7}

Dado que los conjuntos carecen de índice, no es posible acceder a un elemento específico de los que componen un conjunto, pero sí es posible transformar conjuntos en listas o tuplas, como también lo es convertir ambas en conjuntos. Para ello emplearemos los denominados "constructores de clase": list(), tuple() y set(). Este constructor también es necesario para crear un conjunto vacío, ya que no podemos hacerlo directamente:
  • Conjunto vacío: c0=set() -> devuelve set()
  • Conjunto a partir de lista: cl=set([1,2,3]) -> devuelve set{1,2,3}
  • Lista a partir de conjunto: lc = list({1,2,3} -> devuelve [1,2,3]
  • Conjunto a partir de tupla: ct=set((2,5,7)) -> devuelve {2,5,7}
  • Tupla a partir de conjunto: tc=tuple({3,4,5}) -> devuelve (3,4,5)
Si queremos obtener el contenido individual de una determinada posición en un conjunto, primero deberemos obtener el orden que ocupa ese elemento en el conjunto, ya que no es igual al orden en que lo introducimos, y después convertirlo en lista o tupla y solicitar la posición que nos interese. Por ejemplo:

cj={24,"pato","9",2.3}  -> Creamos el conjunto
print(cj) -> Comprobamos el orden {24, '9', 2.3, 'pato'}
ls=list(cj) -> Convertimos el conjunto en una lista
print(ls[0]) -> Solicitamos el dato situado en primer lugar 24

NOTA. En estos casos siempre es preferible trabajar con listas o tuplas, pero podría ser conveniente utilizar conjuntos si el volumen de datos es muy elevado.