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

Python 3.x 3.2

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)}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow