Python Language
Módulo Itertools
Buscar..
Sintaxis
import itertools
Agrupando elementos de un objeto iterable usando una función
Comenzar con un iterable que necesita ser agrupado.
lst = [("a", 5, 6), ("b", 2, 4), ("a", 2, 5), ("c", 2, 6)]
Genere el generador agrupado, agrupando por el segundo elemento en cada tupla:
def testGroupBy(lst):
groups = itertools.groupby(lst, key=lambda x: x[1])
for key, group in groups:
print(key, list(group))
testGroupBy(lst)
# 5 [('a', 5, 6)]
# 2 [('b', 2, 4), ('a', 2, 5), ('c', 2, 6)]
Sólo se agrupan grupos de elementos consecutivos. Es posible que deba ordenar por la misma clave antes de llamar a groupby For Eg, (el último elemento ha cambiado)
lst = [("a", 5, 6), ("b", 2, 4), ("a", 2, 5), ("c", 5, 6)]
testGroupBy(lst)
# 5 [('a', 5, 6)]
# 2 [('b', 2, 4), ('a', 2, 5)]
# 5 [('c', 5, 6)]
El grupo devuelto por groupby es un iterador que no será válido antes de la próxima iteración. Por ejemplo, lo siguiente no funcionará si desea que los grupos se ordenen por clave. El grupo 5 está vacío a continuación porque cuando se busca el grupo 2 invalida 5
lst = [("a", 5, 6), ("b", 2, 4), ("a", 2, 5), ("c", 2, 6)]
groups = itertools.groupby(lst, key=lambda x: x[1])
for key, group in sorted(groups):
print(key, list(group))
# 2 [('c', 2, 6)]
# 5 []
Para realizar correctamente la clasificación, cree una lista desde el iterador antes de ordenar
groups = itertools.groupby(lst, key=lambda x: x[1])
for key, group in sorted((key, list(group)) for key, group in groups):
print(key, list(group))
# 2 [('b', 2, 4), ('a', 2, 5), ('c', 2, 6)]
# 5 [('a', 5, 6)]
Toma una rebanada de un generador
Itertools "islice" le permite cortar un generador:
results = fetch_paged_results() # returns a generator
limit = 20 # Only want the first 20 results
for data in itertools.islice(results, limit):
print(data)
Normalmente no se puede cortar un generador:
def gen():
n = 0
while n < 20:
n += 1
yield n
for part in gen()[:3]:
print(part)
Daré
Traceback (most recent call last):
File "gen.py", line 6, in <module>
for part in gen()[:3]:
TypeError: 'generator' object is not subscriptable
Sin embargo, esto funciona:
import itertools
def gen():
n = 0
while n < 20:
n += 1
yield n
for part in itertools.islice(gen(), 3):
print(part)
Tenga en cuenta que al igual que una división normal, también puede usar los argumentos de start
, stop
y step
:
itertools.islice(iterable, 1, 30, 3)
itertools.product
Esta función le permite recorrer el producto cartesiano de una lista de iterables.
Por ejemplo,
for x, y in itertools.product(xrange(10), xrange(10)):
print x, y
es equivalente a
for x in xrange(10):
for y in xrange(10):
print x, y
Como todas las funciones de python que aceptan un número variable de argumentos, podemos pasar una lista a itertools.product para desempaquetar, con el operador *.
Así,
its = [xrange(10)] * 2
for x,y in itertools.product(*its):
print x, y
produce los mismos resultados que los dos ejemplos anteriores.
>>> from itertools import product
>>> a=[1,2,3,4]
>>> b=['a','b','c']
>>> product(a,b)
<itertools.product object at 0x0000000002712F78>
>>> for i in product(a,b):
... print i
...
(1, 'a')
(1, 'b')
(1, 'c')
(2, 'a')
(2, 'b')
(2, 'c')
(3, 'a')
(3, 'b')
(3, 'c')
(4, 'a')
(4, 'b')
(4, 'c')
itertools.count
Introducción:
Esta simple función genera infinitas series de números. Por ejemplo...
for number in itertools.count():
if number > 20:
break
print(number)
Tenga en cuenta que hay que romper o se imprime para siempre!
Salida:
0
1
2
3
4
5
6
7
8
9
10
Argumentos:
count()
toma dos argumentos, start
y step
:
for number in itertools.count(start=10, step=4):
print(number)
if number > 20:
break
Salida:
10
14
18
22
itertools.takewhile
itertools.takewhile le permite tomar elementos de una secuencia hasta que una condición se convierte en False
.
def is_even(x):
return x % 2 == 0
lst = [0, 2, 4, 12, 18, 13, 14, 22, 23, 44]
result = list(itertools.takewhile(is_even, lst))
print(result)
Esto produce [0, 2, 4, 12, 18]
.
Tenga en cuenta que, el primer número que viola el predicado (es decir, la función que devuelve un valor booleano) is_even
is, 13
. Una vez que takewhile
encuentra un valor que produce False
para el predicado dado, se rompe.
La salida producida por takewhile
es similar a la salida generada a partir del código siguiente.
def takewhile(predicate, iterable):
for x in iterable:
if predicate(x):
yield x
else:
break
Nota: La concatenación de los resultados producidos por takewhile
y dropwhile
produce el iterable original.
result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))
itertools.dropwhile
itertools.dropwhile le permite tomar elementos de una secuencia después de que una condición se convierte en False
.
def is_even(x):
return x % 2 == 0
lst = [0, 2, 4, 12, 18, 13, 14, 22, 23, 44]
result = list(itertools.dropwhile(is_even, lst))
print(result)
Esto da como resultado [13, 14, 22, 23, 44]
.
( Este ejemplo es el mismo que el de takewhile
pero usando dropwhile
) .
Tenga en cuenta que, el primer número que viola el predicado (es decir, la función que devuelve un valor booleano) is_even
is, 13
. Todos los elementos antes de eso, se descartan.
La salida producida por dropwhile
es similar a la salida generada a partir del código a continuación.
def dropwhile(predicate, iterable):
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
La concatenación de los resultados producidos por takewhile
y dropwhile
produce el iterable original.
result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))
Zipping dos iteradores hasta que ambos están agotados
Similar a la función incorporada zip()
, itertools.zip_longest
continuará iterando más allá del final del más corto de los dos iterables.
from itertools import zip_longest
a = [i for i in range(5)] # Length is 5
b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] # Length is 7
for i in zip_longest(a, b):
x, y = i # Note that zip longest returns the values as a tuple
print(x, y)
Se puede pasar un argumento de valor de fillvalue
opcional (predeterminado a ''
) de la siguiente manera:
for i in zip_longest(a, b, fillvalue='Hogwash!'):
x, y = i # Note that zip longest returns the values as a tuple
print(x, y)
En Python 2.6 y 2.7, esta función se llama itertools.izip_longest
.
Método de combinaciones en el módulo Itertools
itertools.combinations
devolverá un generador de la secuencia de combinación k de una lista.
En otras palabras: devolverá un generador de tuplas de todas las combinaciones posibles de k de la lista de entrada.
Por ejemplo:
Si tienes una lista:
a = [1,2,3,4,5]
b = list(itertools.combinations(a, 2))
print b
Salida:
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
La salida anterior es un generador convertido a una lista de tuplas de todas las combinaciones posibles de pares de la lista de entrada a
También puedes encontrar todas las 3 combinaciones:
a = [1,2,3,4,5]
b = list(itertools.combinations(a, 3))
print b
Salida:
[(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4),
(1, 3, 5), (1, 4, 5), (2, 3, 4), (2, 3, 5),
(2, 4, 5), (3, 4, 5)]
Encadenando múltiples iteradores juntos
Use itertools.chain
para crear un solo generador que produzca los valores de varios generadores en secuencia.
from itertools import chain
a = (x for x in ['1', '2', '3', '4'])
b = (x for x in ['x', 'y', 'z'])
' '.join(chain(a, b))
Resultados en:
'1 2 3 4 x y z'
Como constructor alternativo, puede usar el método chain.from_iterable
que toma como único parámetro un iterable de iterables. Para obtener el mismo resultado que arriba:
' '.join(chain.from_iterable([a,b])
Mientras que chain
puede tomar un número arbitrario de argumentos, chain.from_iterable
es la única manera de encadenar un número infinito de iterables.
itertools.repeat
Repetir algo n veces:
>>> import itertools
>>> for i in itertools.repeat('over-and-over', 3):
... print(i)
over-and-over
over-and-over
over-and-over
Obtener una suma acumulada de números en un iterable
accumulate
rendimientos una suma acumulada (o producto) de números.
>>> import itertools as it
>>> import operator
>>> list(it.accumulate([1,2,3,4,5]))
[1, 3, 6, 10, 15]
>>> list(it.accumulate([1,2,3,4,5], func=operator.mul))
[1, 2, 6, 24, 120]
Recorre los elementos en un iterador
cycle
es un iterador infinito.
>>> import itertools as it
>>> it.cycle('ABCD')
A B C D A B C D A B C D ...
Por lo tanto, tenga cuidado de dar límites al usar esto para evitar un bucle infinito. Ejemplo:
>>> # Iterate over each element in cycle for a fixed range
>>> cycle_iterator = it.cycle('abc123')
>>> [next(cycle_iterator) for i in range(0, 10)]
['a', 'b', 'c', '1', '2', '3', 'a', 'b', 'c', '1']
itertools.permutaciones
itertools.permutations
devuelve un generador con permutaciones sucesivas de longitud r de elementos en el iterable.
a = [1,2,3]
list(itertools.permutations(a))
# [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
list(itertools.permutations(a, 2))
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
Si la lista a
tiene elementos duplicados, las permutaciones resultantes tendrán elementos duplicados, puede usar set
para obtener permutaciones únicas:
a = [1,2,1]
list(itertools.permutations(a))
# [(1, 2, 1), (1, 1, 2), (2, 1, 1), (2, 1, 1), (1, 1, 2), (1, 2, 1)]
set(itertools.permutations(a))
# {(1, 1, 2), (1, 2, 1), (2, 1, 1)}