Una de las cosas más maravillosas de las compus es que podemos repetir un mismo cálculo para muchos valores de forma automática. Ya hemos visto al menos un iterator
(iterador), que no es una lista... es otro objeto.
In [2]:
for i in range(10):
print(i, end=' ')
Pero range
, la verdad no es una lista. Es un iterador y aprender cómo funciona es útil en varios ámbitos.
In [3]:
for value in [2, 4, 6, 8, 10]:
# do some operation
print(value + 1, end=' ')
En este caso, lo primero que hace el iterador es chequear si el objeto del otro lado del in
es un iterador. Esto se puede chequear con la función iter
, parecida a type
.
In [4]:
iter([2, 4, 6, 8, 10])
Out[4]:
In [5]:
I = iter([2, 4, 6, 8, 10])
In [6]:
print(next(I))
In [7]:
print(next(I))
range()
como una lista, expone un iterador:
In [8]:
range(10)
Out[8]:
In [9]:
iter(range(10))
Out[9]:
Y es así como Python lo trata como si fuera una lista:
In [10]:
N = 10 ** 12
for i in range(N):
if i >= 10: break
print(i, end=', ')
Si una lista fuera a crear un trillón de valores ($10^{12}$), necesitaríamos terabytes de memoria para almacenarlos.
Algunas veces queremos no solo iterar sobre los valores en una lista, sino también imprimir el índice de ellos.
In [11]:
L = [2, 4, 6, 8, 10]
for i in range(len(L)):
print(i, L[i])
Pero hay una sintaxis más limpia para esto:
In [12]:
for i, val in enumerate(L):
print(i, val)
La función zip
itera sobre dos iterables y produce una tupla:
In [13]:
L = [2, 4, 6, 8, 10]
R = [3, 6, 9, 12, 15]
for lval, rval in zip(L, R):
print(lval, rval)
Si las listas son de diferente largo, el largo del zip
va a estar dado por la lista más corta.
Un poco más intenso: el iterador map
toma una función y la aplica sobre todos los valores de un iterador:
In [14]:
# find the first 10 square numbers
square = lambda x: x ** 2
for val in map(square, range(10)):
print(val, end=' ')
El iterador filter
toma una función y la aplica sobre todos los valores de un iterador devolviendo sólo aquellos valores que "pasan" el filtro.
In [15]:
# find values up to 10 for which x % 2 is zero
is_even = lambda x: x % 2 == 0
for val in filter(is_even, range(10)):
print(val, end=' ')
Ya vimos el count
de itertools
. Este módulo contiene un montón de funciones útiles. Por ejemplo, aqui veremos itertools.permutations
, itertools.combinations
, itertools.product
.
In [16]:
from itertools import permutations
p = permutations(range(3))
print(*p)
In [18]:
from itertools import combinations
c = combinations(range(4), 2)
print(*c)
In [19]:
from itertools import product
p = product('ab', range(3))
print(*p)