Anteriormente vimos que podríamos iterar directamente sobre una lista con la siguiente sintaxis:
for element in somelist:
...
La cual podemos iterar usando una lista de índices y un índice dentro del ciclo:
for i in range(len(somelist)):
element = somelist[i]
Ejemplo: usando índices, generar dos listas con los grados Celsius y los grados Fahrenheit y después con un sólo ciclo imprimir la tabla de conversión desde -10 hasta 40 grados Celsius con intervalos de 2.5
Cdegrees = []
n = 21
C_min = -10
C_max = 40
dC = (C_max - C_min) / float(n - 1)
for i in range(n):
C = -10 + i * dC
Cdegrees.append(C)
Fdegrees = []
for C in Cdegrees:
F = (9.0/5) * C + 32
Fdegrees.append(F)
for i in range(len(Cdegrees)):
C = Cdegrees[i]
F = Fdegrees[i]
print("%5.1f %5.1f"% (C, F))
Otra forma de construir listas es usando la notación:
lista = [0] * n
La cuál creará una lista de tamaño n llena de ceros. Usando esta construcción, podemos reescribir el código anterior de la siguiente forma:
n = 21; C_min = -10; C_max = 40; dC = (C_max - C_min) / float(n - 1)
Cdegrees = [0] * n
for i in range(len(Cdegrees)):
Cdegrees[i] = -10 + i*dC
Fdegrees = [0] * n
for i in range(len(Cdegrees)):
Fdegrees[i] = (9.0/5)*Cdegrees[i] + 32
for i in range(len(Cdegrees)):
print("%5.1f %5.1f" % (Cdegrees[i], Fdegrees[i])
Tenemos dos formas alternativas de recorrer una lista, ya sea sobre elementos o sobre índices. Supongamos que queremos cambiar la lista Cdegrees por agregar 5 a cada elemento. Podemos intentar:
for c in Cdegrees:
c += 5
Pero también podemos:
for i in range(len(Cdegrees)):
Cdegrees[i] += 5
¿Qué es lo que sucede con ambas ejecuciones?
Vimos que el último ciclo se encarga de actualizar los valores de la lista. Además de esa forma, existe una forma de recorrer una lista de tal forma que obtengamos el índice y el elemento de la lista. Esta construcción la tenemos de la siguiente forma:
for i, c in enumerate(Cdegrees):
Cdegrees[i] = c + 5
Debido a que el recorrido dentro de una lista y crear elementos dentro de la misma, es una tarea frecuente, Python tiene una sintaxis compacta para hacer esto, llamado Comprensión de listas (list comprehension). La sintaxis general es:
newlist = [E(e) for e in list]
Donde E(e) representa una expresión envolviendo al elemento e. Aquí hay tres ejemplos:
Cdegrees = [-5 + i * 0.5 for i in range(n)]
Fdegrees = [(9.0/5) * C + 32 for C in Cdegrees]
C_plus_4 = [C + 5 for C in Cdegrees]
Anteriormente generamos una tabla de conversión usando Cdegrees y Fdegrees. Para hacerlo necesitamos recorrer ambas listas. Usar la sintaxis for element in list no es útil para nuestro proposito y no queremos usar indices. Python va proveer una alternativa a este problema usando la siguiente sintaxis:
for e1, e2, e3, ... in zip(list1, list2, list3):
<usar e1, e2, e3, etc...>
La función zip transforma las n listas (list1, list2, *list3, …) en una lista de n-tuplas, donde cada n-tupla (e1, e2, e3, ..) tiene su primer elemento (e1) desde la primera lista (list1), el segundo elemnto (e2) desde la segunda lista (list2) y así sucesivamente.
for C, F in zip(Cdegrees, Fdegrees):
print("%5.1f %5.1f"%(C,F))
Las listas anidadas son listas cuyos elementos en la lista son listas en si mismas.
Por ejemplo, podemos tener una lista con las listas Cdegrees y Fdegrees que represente nuestra tabla.
Cdegrees = list(range(-20, 41, 5))
Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees]
table = [Cdegrees, Fdegrees]
xo
>> [[-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
, [-4.0, 5.0, 14.0, 23.0, 32.0, 41.0, 50.0, 59.0, 68.0, 77.0, 86.0, 95.0, 104.0]]
A pesar de lo anterior, quisieramos tener una lista que tuvieras listas de dos elementos que representen parejas [C, F] y para tener esto necesitamos la siguiente construcción:
table = []
for C, F in zip(Cdegrees, Fdegrees):
table.append([C, F])
o de forma más compacta:
table = [[C, F] for C, F in zip(Cdegrees, Fdegrees)]
Python provee un módulo para imprimir objetos de forma bonita. Este módulo es pprint:
import pprint
pprint.print(table)
Además de que scitools va proveer un módulo para proveer total control sobre la impresión de números flotantes dentro de listas.
import pprint, scitools.pprint2
somelist = [15.8, [0.2, 1.7]]
pprint.pprint(somelist)
#[15.800000000000001, [0.20000000000000001, 1.7]]
scitools.pprint2.pprint(somelist)
# [15.8, [0.2, 1.7]]
>>> # default output is ’%g’, change this to
scitools.pprint2.float_format = ’%.2e’
scitools.pprint2.pprint(somelist)
# [1.58e+01, [2.00e-01, 1.70e+00]
Python tiene una bonita sintaxis para extraer partes de una listas. Estas partes son conocidas como sublistas o slices.
- A{i:]
- Es la sublista iniciando en el índice i y continuando hasta el final de A.
A = [2, 3.5, 8, 10]
A[2:]
- A[i:j]
- Es la sublista iniciando en en el índice i y terminando en el índice j - 1.
A[1:3]
- A[:j]
- Es la sublista que inicia en el índice 0 y termina en el índice j-1 de A.
A[:3]
- A[1:-1]
- Extrae todos los elementos excepto el último y el primero.
- A[:]
- Es toda la lista
También podemos extraer sublistas de listas anidadas:
table[4:]
table[4:7][0:2]
Las sublistas son siempre copias de lista de original, así que si modificamos las sublistas, la lista original se mantiene sin cambios.
l1 = [1, 4, 3]; l2 = l1[:-1]
l2
l1[0] = 100
l1; l2
El hecho de que crear sublistas son copias, puede ser ilustrado con el siguiente código:
B = A[:]
C = A
B == A
B is A
C is A
Vimos anteriormente que recorrer la lista anidada table puede ser hecho de la siguiente forma:
for C, F in table:
<to do something>
Supongamos ahora que necesitamos una lista anidada de puntajes scores para llevar el control de puntos de varios jugadores. La lista scores[i] representa los puntajes del jugador i.
Cada una de las listas scores[i] tiene distinto tamaño, entonces, ¿Cómo recorremos las listas?
scores = []
scores.append([12, 16, 11, 12])
scores.append([9])
scores.append([6, 9, 11, 14, 17, 15, 14, 20])
Hay dos formas de recorrer esta lista:
for p in range(len(scores)):
for g in range(len(scores[p])):
print("%4d"%score)
print
for player in scores:
for point in player:
print("%4d"%score)
print
Las tuplas son muy similares a las listas, pero las tuplas no permiten cambios. Esto es, las tuplas pueden ser vistas como listas constantes.
t = (2, 4, 6, 'temp.pdf')
t1 = 2, 4, 6, 'temp.pdf'
for element in 'myfile.txt', 'yourfile.txt', 'herfile.txt':
print(element)
Muchas de las funciones usadas para las listas, también se encuentran disponibles para las tuplas. Por ejemplo:
t = t + (-1.0, -2.0)
t
t[1]
t[2:]
6 in t
Mientras que las operaciones de modificación no van a funcionar:
>>> t[1] = -1
...
TypeError: object does not support item assignment
>>> t.append(0)
...
AttributeError: ’tuple’ object has no attribute ’append’
>>> del t[1]
...
TypeError: object doesn't support item deletion
¿Cuándo necesitamos usar tuplas cuando podemos hacer más con listas?
- Las tuplas protegen contra cambios accidentales en sus contenidos
- Código basado en listas es mucho más rápido que en listas
- Las tuplas son frecuentemente usadas en software hecho en Python que seguramente vas a hacer uso de el, así que necesitas conocer este tipo de datos.
Dado un arreglo de números enteros aleatorios, encontrar el par de números cuya suma sea más cercana a cero. Por ejemplo, en el arreglo [45, -29, -96, -7, -17, 72, -60], los dos enteros cuya suma es más cercana a cero son -60 y 72.
La tarea es escribir un programa que encuentre la suma más cercana a cero.
Solución
def cercano_a_cero(int_array):
cercano_a_cero = [float("inf")]
for index, operando1 in enumerate(int_array):
for operando2 in list(int_array[index+1:]):
suma_ints = [operando1, operando2]
if abs(sum(suma_ints)) < abs(sum(cercano_a_cero)):
cercano_a_cero = suma_ints
return cercano_a_cero
if __name__ == "__main__":
print(cercano_a_cero([45, -29, -96, -7, -17, 72, -60]))