¿Qué son las funciones de Python Itertools?

De acuerdo con la documentación de Python, Itertools es un módulo de Python que proporciona un conjunto de herramientas rápidas y eficientes en memoria para trabajar con iteradores de Python. Estas herramientas se pueden usar solas o en combinación, y hacen posible crear y trabajar con iteradores de manera sucinta y eficiente de una manera rápida y eficiente en memoria.

El módulo de Itertools contiene funciones que facilitan el trabajo con iteradores, especialmente cuando se manejan grandes conjuntos de datos. Las funciones de Itertools pueden funcionar en iteradores existentes para crear iteradores de Python aún más complejos.

Además, Itertools puede ayudar a los desarrolladores a reducir los errores al trabajar con iteradores y escribir código más limpio, legible y fácil de mantener.

Según la funcionalidad que proporcionan los iteradores en el módulo de Itertools, se pueden clasificar en los siguientes tipos:

#1. Iteradores infinitos

Estos son iteradores que le permiten trabajar con secuencias infinitas y ejecutar un ciclo infinitamente si no hay una condición para salir del ciclo. Dichos iteradores son útiles cuando se simulan bucles infinitos o se genera una secuencia ilimitada. Itertools tiene tres iteradores infinitos, que incluyen contar(), ciclo() y repetir().

#2. iteradores combinatorios

Los iteradores combinatorios comprenden funciones que se pueden usar para trabajar en productos cartesianos y realizar combinaciones y permutaciones de elementos contenidos dentro de un iterable. Estas son las funciones de acceso cuando se trata de encontrar todas las formas posibles de organizar o combinar elementos en un iterable. Itertools tiene cuatro iteradores combinatorios. Estos son producto(), permutaciones(), combinaciones() y combinaciones_con_reemplazo().

#3. Iteradores que terminan en la secuencia de entrada más corta

Estos son iteradores de terminación que se utilizan en secuencias finitas y generan una salida basada en el tipo de función utilizada. Los ejemplos de estos iteradores de terminación incluyen: Accumulate(), Chain(), Chain.from_iterable(), Compress(), Dropwhile(), Filterfalse(), Groupby(), Islice(), Pairwise(), Starmap(), Takewhile. (), tee() y zip_longest().

Veamos cómo funcionan las diferentes funciones de Itertools según su tipo:

Iteradores infinitos

Los tres iteradores infinitos incluyen:

#1. contar()

La función contar (inicio, paso) genera una secuencia infinita de números a partir del valor inicial. La función toma dos argumentos opcionales: inicio y paso. El inicio del argumento establece dónde debe comenzar la secuencia de números. De forma predeterminada, comienza en 0 si no se proporciona un valor de inicio. paso establece la diferencia entre cada número consecutivo. El valor de paso predeterminado es 1.

import itertools
# count starting at 4, making steps of 2  
for i in itertools.count(4, 2):
    # condition to end the loop avoiding infinite looping
    if i == 14:
        break
    else:
        print(i) # output - 4, 6, 8, 10, 12

Producción

4
6
8
10
12

#2. ciclo()

La función de ciclo (iterable) toma un iterable como argumento y luego recorre el iterable permitiendo el acceso a los elementos en el iterable en el orden en que aparecen.

Por ejemplo, si pasamos [“red”, “green”, “yellow”] en ciclo(), en el primer ciclo, tendremos acceso a «rojo»; en el segundo ciclo tendremos acceso a «verde», luego «amarillo». En el cuarto ciclo, dado que todos los elementos se han agotado en el iterable, comenzaremos de nuevo en «rojo» y luego continuaremos infinitamente.

Al llamar a Cycle(), almacena su resultado en una variable para crear un iterador que mantiene su estado. Esto asegura que el ciclo no comience de nuevo cada vez, brindándole acceso solo al primer elemento.

import itertools

colors = ["red", "green", "yellow"]
# pass in colors into cycle()
color_cycle = itertools.cycle(colors)
print(color_cycle)

# range used to stop the infinite loop once we've printed 7 times
# next() used to return the next item from the iterator
for i in range(7):
    print(next(color_cycle))

Producción:

red
green
yellow
red
green
yellow
red

#3. repetir()

repetir (elem, n) toma dos argumentos, un elemento para repetir (elem) y la cantidad de veces que desea repetir el elemento (n). El elemento que desea repetir puede ser un valor único o iterable. Si no pasa, n, el elemento se repetirá infinitamente.

import itertools
   
for i in itertools.repeat(10, 3):
    print(i)

Producción:

10 
10
10

iteradores combinatorios

Los iteradores combinatorios incluyen:

#1. producto()

product() es una función utilizada para calcular el producto cartesiano del iterable que se le pasa. Si tenemos dos iterables o conjuntos, por ejemplo, x = {7,8} e y = {1,2,3}, el producto cartesiano de xey contendrá todas las combinaciones posibles de elementos de xey, donde el el primer elemento es de x y el segundo de y. El producto cartesiano de x e y en este caso es [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)].

product() toma un parámetro opcional llamado repetición que se usa para calcular el producto cartesiano de un iterable consigo mismo. repetir especifica el número de repeticiones para cada elemento de los iterables de entrada al calcular el producto cartesiano.

Por ejemplo, llamar a producto(‘ABCD’, repetir=2) produce combinaciones como (‘A’, ‘A’), (‘A’, ‘B’), (‘A’, ‘C’), y así en. Si repetir se estableciera en 3, la función produciría combinaciones como (‘A’, ‘A’, ‘A’), (‘A’, ‘A’, ‘B’), (‘A’, ‘A’ , ‘C’), (‘A’, ‘A’, ‘D’) y así sucesivamente.

from itertools import product
# product() with the optional repeat argument
print("product() with the optional repeat argument ")
print(list(product('ABC', repeat = 2)))

# product with no repeat
print("product() WITHOUT an optional repeat argument")
print(list(product([7,8], [1,2,3])))

Producción

product() with the optional repeat argument 
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
product() WITHOUT an optional repeat argument
[(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]

#2. permutaciones()

permutations(iterable, group_size) devuelve todas las permutaciones posibles del iterable que se le pasó. Una permutación representa el número de formas en que se pueden ordenar los elementos de un conjunto. permutations() toma un argumento opcional group_size. Si no se especifica group_size, las permutaciones generadas tendrán el mismo tamaño que la longitud del iterable pasado a la función

import itertools
numbers = [1, 2, 3]
sized_permutations = list(itertools.permutations(numbers,2))
unsized_permuatations = list(itertools.permutations(numbers))

print("Permutations with a size of 2")
print(sized_permutations)
print("Permutations with NO size argument")
print(unsized_permuatations)

Producción

Permutations with a group size of 2
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
Permutations with NO size argument
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

#3. combinaciones()

combinaciones (iterable, tamaño) devuelve todas las combinaciones posibles de un iterable de una longitud dada de los elementos en el iterable pasado a la función. El argumento de tamaño especifica el tamaño de cada combinación.

Los resultados están ordenados. La combinación difiere ligeramente de las permutaciones. Con la permutación, el orden importa, pero con la combinación, el orden no importa. por ejemplo, en [A, B, C] hay 6 permutaciones: AB, AC, BA, BC, CA, CB pero solo 3 combinaciones AB, AC, BC.

import itertools
numbers = [1, 2, 3,4]
size2_combination = list(itertools.combinations(numbers,2))
size3_combination = list(itertools.combinations(numbers, 3))

print("Combinations with a size of 2")
print(size2_combination)
print("Combinations with a size of 3")
print(size3_combination)

Producción:

Combinations with a size of 2
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
Combinations with a size of 3
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]

#4. combinaciones_con_reemplazo()

combinaciones_con_reemplazo(iterable, tamaño) genera todas las combinaciones posibles de un iterable de una longitud dada del iterable pasado a la función y permite elementos repetidos en las combinaciones de salida. El tamaño determina el tamaño de las combinaciones generadas.

Esta función se diferencia de las combinaciones () en que proporciona combinaciones en las que un elemento se puede repetir más de una vez. Por ejemplo, puede obtener una combinación como (1,1) que no puede obtener con combinación().

import itertools
numbers = [1, 2, 3,4]

size2_combination = list(itertools.combinations_with_replacement(numbers,2))
print("Combinations_with_replacement => size 2")
print(size2_combination)

Producción

Combinations_with_replacement => size 2
[(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]

Iteradores de terminación

Esto incluye iteradores como:

#1. acumular()

acumular (iterable, función) toma un argumento iterable y un segundo opcional que es una función. Luego devuelve el resultado acumulado de aplicar la función en cada iteración sobre elementos en el iterable. Si no se pasa ninguna función, se realiza la suma y se devuelven los resultados acumulados.

import itertools
import operator
numbers = [1, 2, 3, 4, 5]

# Accumulate the sum of numbers
accumulated_val = itertools.accumulate(numbers)
accumulated_mul = itertools.accumulate(numbers, operator.mul)
print("Accumulate with no function")
print(list(accumulated_val))
print("Accumulate with multiplication")
print(list(accumulated_mul))

Producción:

Accumulate with no function
[1, 3, 6, 10, 15]
Accumulate with multiplication
[1, 2, 6, 24, 120]

#2. cadena()

chain(iterable_1, iterable_2, …) toma múltiples iterables y los encadena juntos produciendo un solo iterable que contiene valores de los iterables pasados ​​a la función chain()

import itertools

letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']

# Chain letters and numbers together
chained_iterable = list(itertools.chain(letters, numbers, colors))
print(chained_iterable)

Producción:

['A', 'B', 'C', 'D', 1, 2, 3, 'red', 'green', 'yellow']

#3. cadena.de_iterable()

chain.from_iterable(iterable) esta función es similar a chain(). Sin embargo, se diferencia de la cadena en que solo toma un único iterable que contiene sub-iterables y los encadena.

import itertools

letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']

iterable = ['hello',colors, letters, numbers]
chain = list(itertools.chain.from_iterable(iterable))
print(chain)

Producción:

['h', 'e', 'l', 'l', 'o', 'red', 'green', 'yellow', 'A', 'B', 'C', 'D', 1, 2, 3]

#4. comprimir()

compress(data, selectors) toma dos argumentos, datos que son iterables y selectores que son iterables que contienen valores booleanos verdaderos y falsos. 1, 0 también se puede utilizar como alternativa a los valores booleanos verdadero y falso. compress() luego filtra los datos pasados ​​usando los elementos correspondientes pasados ​​en el selector.

Se seleccionan los valores en datos que corresponden al valor verdadero o 1 en el selector, mientras que el resto que corresponden a falso o 0 se ignoran. Si pasa menos booleanos en los selectores que la cantidad de elementos en los datos, todos los elementos más allá de los booleanos pasados ​​en los selectores se ignoran

import itertools

# data has 10 items
data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
# passing in 9 selector items
selectors = [True, False, 1, False, 0, 1, True, False, 1]

# Select elements from data based on selectors
filtered_data = list(itertools.compress(data, selectors))
print(filtered_data)

Producción:

['A', 'C', 'F', 'G', 'I']

#5. soltar mientras()

dropwhile(función, secuencia) toma una función con la condición que devuelve verdadero o falso y una secuencia de valores. Luego elimina todos los valores hasta que la condición pasada devuelve False. Una vez que la condición devuelve falso, el resto de los elementos se incluyen en sus resultados independientemente de si devolverían Verdadero o Falso.

import itertools

numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

# Drop elements until the passed condition is False
filtered_numbers = list(itertools.dropwhile(lambda x: x < 5, numbers))
print(filtered_numbers)

Producción:

[5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

#6. filtrofalso()

filterfalse(función, secuencia) toma una función, con una condición que se evalúa como verdadera o falsa y una secuencia. Luego devuelve valores de la secuencia que no satisfacen la condición en la función.

import itertools

numbers = [1, 2, 3, 4, 2, 3 5, 6, 5, 8, 1, 2, 3, 6, 2, 7, 4, 3]

# Filter elements for which condition is False
filtered_numbers = list(itertools.filterfalse(lambda x: x < 4, numbers))
print(filtered_numbers)

Producción:

[4, 5, 6, 5, 8, 6, 7, 4]

#7. agrupar por()

groupby(iterable, key) toma un iterable y una clave, luego crea un iterador que devuelve claves y grupos consecutivos. Para que funcione, el iterable que se le pasa debe ordenarse en la misma función clave. La función clave computa un valor clave para cada elemento en el iterable.

import itertools

input_list = [("Domestic", "Cow"), ("Domestic", "Dog"), ("Domestic", "Cat"),("Wild", "Lion"), ("Wild", "Zebra"), ("Wild", "Elephant")]
classification = itertools.groupby(input_list,lambda x: x[0])
for key,value in classification:
  print(key,":",list(value))

Producción:

Domestic : [('Domestic', 'Cow'), ('Domestic', 'Dog'), ('Domestic', 'Cat')]
Wild : [('Wild', 'Lion'), ('Wild', 'Zebra'), ('Wild', 'Elephant')]

#8. islice()

islice(iterable, start, stop, step) le permite dividir un iterable usando los valores de inicio, parada y paso pasados. El argumento del paso es opcional. El conteo comienza desde 0 y el artículo en el número de parada no está incluido.

import itertools

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

# Select elements within a range
selected_numbers = list(itertools.islice(numbers, 2, 10))
selected_numbers_step= list(itertools.islice(numbers, 2, 10,2))
print("islice without setting a step value")
print(selected_numbers)
print("islice with a step value of 2")
print(selected_numbers_step)

Producción:

islice without setting a step value
[3, 4, 5, 6, 7, 8, 9, 10]
islice with a step value of 2
[3, 5, 7, 9]

#9. por parejas()

pairwise(iterable) devuelve pares superpuestos sucesivos tomados del iterable que se le pasó en el orden en que aparecen en el iterable. Si el iterable que se le pasa tiene menos de dos valores, el resultado de pairwise() estará vacío.

from itertools import pairwise

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
word = 'WORLD'
single = ['A']

print(list(pairwise(numbers)))
print(list(pairwise(word)))
print(list(pairwise(single)))

Producción:

[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
[('W', 'O'), ('O', 'R'), ('R', 'L'), ('L', 'D')]
[]

#10. mapa estelar()

starmap(function, iterable) es una función que se usa en lugar de map() cuando los parámetros de argumento ya están agrupados en tuplas. startmap() aplica una función a los elementos del iterable que se le pasa. El iterable debe tener elementos agrupados en tuplas.

import itertools

iter_starmap = [(123, 63, 13), (5, 6, 52), (824, 51, 9), (26, 24, 16), (14, 15, 11)]
print (list(itertools.starmap(min, iter_starmap)))

Producción:

[13, 5, 9, 16, 11]

#11. toma mientras()

takewhile(función, iterable) funciona de manera opuesta a dropwhile(). takewhile() toma una función con una condición para ser evaluada y un iterable. Luego incluye todos los elementos en el iterable que satisfacen la condición en la función hasta que se devuelve False. Una vez que se devuelve False, se ignoran todos los siguientes elementos en el iterable.

import itertools

numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

# Drop elements until the passed condition is False
filtered_numbers = list(itertools.takewhile(lambda x: x < 5, numbers))
print(filtered_numbers)

Producción:

[1, 2, 3, 4]

#12. tee()

tee(iterable, n) toma un iterable y devuelve múltiples iteradores independientes. El número de iteradores a devolver está establecido por n, que por defecto es 2.

import itertools

numbers = [1, 2, 3, 4, 5]

# Create two independent iterators from numbers
iter1, iter2 = itertools.tee(numbers, 2)
print(list(iter1))
print(list(iter2))

Producción:

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

#13. zip_más largo()

zip_longest(iterables, fillvalue) acepta múltiples iteradores y un valor de relleno. Luego devuelve un iterador que agrega elementos de cada uno de los iteradores que se le pasan. Si los iteradores no tienen la misma longitud, los valores que faltan se reemplazan por el valor de relleno pasado a la función hasta que se agota el iterable más largo.

import itertools

names = ['John', 'mathew', 'mary', 'Alice', 'Bob', 'Charlie', 'Fury']
ages = [25, 30, 12, 13, 42]

# Combine name and ages, filling in missing ages with a dash
combined = itertools.zip_longest(names, ages, fillvalue="-")

for name, age in combined:
    print(name, age)

Producción:

John 25
mathew 30
mary 12
Alice 13
Bob 42
Charlie -
Fury -

Conclusión

Las itertools de Python son un conjunto de herramientas importante para un desarrollador de Python. Las itertools de Python se usan ampliamente en programación funcional, procesamiento y transformación de datos, filtrado y selección de datos, agrupación y agregación, combinación de iterables, combinatoria y cuando se trabaja con secuencias infinitas.

Como desarrollador de Python, se beneficiará enormemente al aprender sobre itertools, así que asegúrese de usar este artículo para familiarizarse con Python Itertools.