Cosa sono le funzioni di Python Itertools?

Secondo la documentazione di Python, Itertools è un modulo Python che fornisce una serie di strumenti veloci ed efficienti in termini di memoria per lavorare con gli iteratori Python. Questi strumenti possono essere utilizzati da soli o in combinazione e consentono di creare e lavorare con gli iteratori in modo succinto ed efficiente in modo rapido ed efficiente in termini di memoria.

Il modulo Itertools contiene funzioni che semplificano il lavoro con gli iteratori, in particolare quando si gestiscono grandi insiemi di dati. Le funzioni di Itertools possono lavorare su iteratori esistenti per creare iteratori Python ancora più complessi.

Inoltre, Itertools può aiutare gli sviluppatori a ridurre gli errori quando lavorano con gli iteratori e a scrivere codice più pulito, leggibile e gestibile.

In base alla funzionalità fornita dagli iteratori nel modulo Itertools, possono essere classificati nei seguenti tipi:

#1. Iteratori infiniti

Questi sono iteratori che ti consentono di lavorare con sequenze infinite ed eseguire un ciclo all’infinito se non viene inserita alcuna condizione per uscire dal ciclo. Tali iteratori sono utili quando si simulano cicli infiniti o si genera una sequenza illimitata. Itertools ha tre iteratori infiniti, che includono count(), cycle() e repeat().

#2. Iteratori combinatori

Gli iteratori combinatori comprendono funzioni che possono essere utilizzate per lavorare su prodotti cartesiani ed eseguire combinazioni e permutazioni di elementi contenuti in un iterabile. Queste sono le funzioni di riferimento quando si cerca di trovare tutti i modi possibili per organizzare o combinare elementi in un iterabile. Itertools ha quattro iteratori combinatori. Questi sono product(), permutations(), combinations() e combinations_with_replacement().

#3. Iteratori che terminano sulla sequenza di input più breve

Si tratta di iteratori di terminazione che vengono utilizzati su sequenze finite e generano un output in base al tipo di funzione utilizzata. Esempi di questi iteratori di terminazione includono: accumulate(), chain(), chain.from_iterable(), compress(), dropwhile(), filterfalse(), groupby(), islice(), pairwise(), starmap(), takewhile (), tee() e zip_longest().

Diamo un’occhiata a come funzionano le diverse funzioni di Itertools in base al loro tipo:

Iteratori infiniti

I tre iteratori infiniti includono:

#1. contare()

La funzione count(start, step) genera una sequenza infinita di numeri partendo dal valore iniziale. La funzione accetta due argomenti facoltativi: start e step. L’argomento start imposta dove dovrebbe iniziare la sequenza di numeri. Per impostazione predefinita, inizia da 0 se non viene fornito un valore iniziale. step imposta la differenza tra ogni numero consecutivo. Il valore di passaggio predefinito è 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

Produzione

4
6
8
10
12

#2. ciclo()

La funzione cycle(iterable) prende un iterable come argomento e quindi scorre l’iterable consentendo l’accesso agli elementi nell’iterable nell’ordine in cui appaiono.

Per esempio, se passiamo dentro [“red”, “green”, “yellow”] into cycle(), nel primo ciclo avremo accesso a “red”; nel secondo ciclo avremo accesso al “verde”, poi al “giallo”. Nel quarto ciclo, essendo tutti gli elementi esauriti nell’iterabile, si ricomincerà da “rosso” e poi si andrà avanti all’infinito.

Quando chiami cycle() memorizzi il suo risultato in una variabile per creare un iteratore che ne mantenga lo stato. Ciò garantisce che il ciclo non ricominci ogni volta, dandoti accesso solo al primo 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))

Produzione:

red
green
yellow
red
green
yellow
red

#3. ripetere()

repeat(elem,n) prende due argomenti, un elemento da ripetere (elem) e il numero di volte che vuoi ripetere l’elemento(n). L’elemento che vuoi ripetere può essere un singolo valore o un iterabile. Se non passi n, l’elemento sarà ripetuto all’infinito.

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

Produzione:

10 
10
10

Iteratori combinatori

Gli iteratori combinatori includono:

#1. Prodotto()

product() è una funzione utilizzata per calcolare il prodotto cartesiano dell’iterabile che gli viene passato. Se abbiamo due iterabili o insiemi, ad esempio x = {7,8} e y = {1,2,3}, il prodotto cartesiano di x e y conterrà tutte le possibili combinazioni di elementi da x e y, dove il il primo elemento è da x e il secondo da y. Il prodotto cartesiano di x e y in questo caso è [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)].

product() accetta un parametro opzionale chiamato repeat che viene utilizzato per calcolare il prodotto cartesiano di un iterabile con se stesso. repeat specifica il numero di ripetizioni per ciascun elemento dagli iterabili di input durante il calcolo del prodotto cartesiano.

Ad esempio, chiamando product(‘ABCD’, repeat=2) si ottengono combinazioni come (‘A’, ‘A’), (‘A’, ‘B’), (‘A’, ‘C’) e così SU. Se ripetizione fosse impostata su 3, la funzione produrrebbe combinazioni come (‘A’, ‘A’, ‘A’), (‘A’, ‘A’, ‘B’), (‘A’, ‘A’ , ‘C’), (‘A’, ‘A’, ‘D’) e così via.

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

Produzione

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. permutazioni()

permutations(iterable, group_size) restituisce tutte le possibili permutazioni dell’iterable passato in esso. Una permutazione rappresenta il numero di modi in cui gli elementi di un insieme possono essere ordinati. permutations() accetta un argomento facoltativo group_size. Se group_size non è specificato, le permutazioni generate avranno la stessa dimensione della lunghezza dell’iterabile passato nella funzione

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)

Produzione

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. combinazioni()

combinations(iterable, size) restituisce tutte le possibili combinazioni di un iterable di una data lunghezza dagli elementi nell’iterable passati alla funzione. L’argomento size specifica la dimensione di ciascuna combinazione.

I risultati sono ordinati. La combinazione differisce leggermente dalle permutazioni. Con la permutazione l’ordine è importante, ma con la combinazione l’ordine non ha importanza. Ad esempio, dentro [A, B, C] ci sono 6 permutazioni: AB, AC, BA, BC, CA, CB ma solo 3 combinazioni 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)

Produzione:

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. combinazioni_con_sostituzione()

combinations_with_replacement(iterable, size) genera tutte le possibili combinazioni di un iterabile di una data lunghezza dall’iterabile passato nella funzione e consente elementi ripetuti nelle combinazioni di output. La dimensione determina la dimensione delle combinazioni generate.

Questa funzione differisce da combinations() in quanto fornisce combinazioni in cui un elemento può essere ripetuto più di una volta. Ad esempio, puoi ottenere una combinazione come (1,1) che non puoi ottenere con combination().

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)

Produzione

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

Iteratori di terminazione

Questo include iteratori come:

#1. accumulare()

accumulate(iterable, function) accetta un iterabile e un secondo argomento facoltativo che è una funzione. Quindi restituisce il risultato accumulato dell’applicazione della funzione in ogni iterazione sugli elementi sull’iterabile. Se non viene passata alcuna funzione, viene eseguita l’addizione e vengono restituiti i risultati accumulati.

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

Produzione:

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

#2. catena()

chain(iterable_1, iterable_2, …) prende più iterable e li concatena insieme producendo un singolo iterable contenente valori dagli iterable passati alla funzione 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)

Produzione:

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

#3. chain.from_iterable()

chain.from_iterable(iterable) questa funzione è simile a chain(). Tuttavia, differisce dalla catena in quanto prende solo un singolo iterabile contenente sub-iterabili e li concatena insieme.

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)

Produzione:

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

#4. comprimere()

compress(data, selectors) accetta due argomenti, data che è un iterabile e selectors che è un iterabile contenente valori booleani true e false. 1, 0 possono anche essere usati come alternative ai valori booleani true e false. compress() quindi filtra i dati passati utilizzando gli elementi corrispondenti passati nel selettore.

I valori nei dati che corrispondono al valore true o 1 nel selettore vengono selezionati, mentre il resto che corrisponde a false o 0 viene ignorato. Se passi meno booleani nei selettori rispetto al numero di elementi nei dati, tutti gli elementi oltre i booleani passati nei selettori vengono ignorati

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)

Produzione:

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

#5. lascia perdere()

dropwhile(funzione, sequenza) accetta una funzione con la condizione che restituisce vero o falso e una sequenza di valori. Quindi elimina tutti i valori fino a quando la condizione superata restituisce False. Una volta che la condizione restituisce false, il resto degli elementi viene incluso nei suoi risultati indipendentemente dal fatto che restituiscano True o False.

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)

Produzione:

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

#6. filtrofalso()

filterfalse(funzione, sequenza) accetta una funzione, con una condizione che restituisce vero o falso e una sequenza. Quindi restituisce i valori dalla sequenza che non soddisfano la condizione nella funzione.

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)

Produzione:

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

#7. raggruppa per()

groupby(iterable, key) accetta un iterabile e una chiave, quindi crea un iteratore che restituisce chiavi e gruppi consecutivi. Perché funzioni, l’iterabile passato deve essere ordinato sulla stessa funzione chiave. La funzione chiave calcola un valore chiave per ogni elemento nell’iterabile.

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

Produzione:

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

#8. islice()

islice(iterable, start, stop, step) consente di suddividere un iterabile utilizzando i valori di start, stop e step passati. L’argomento step è facoltativo. Il conteggio inizia da 0 e l’articolo sul numero di fermata non è incluso.

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)

Produzione:

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. a coppie()

pairwise(iterable) restituisce coppie sovrapposte successive prese dall’iterabile che gli è stato passato nell’ordine in cui appaiono nell’iterabile. Se l’iterabile passato ha meno di due valori, il risultato di pairwise() sarà vuoto.

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

Produzione:

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

#10. mappa stellare()

starmap(function, iterable) è una funzione utilizzata al posto di map() quando i parametri degli argomenti sono già raggruppati in tuple. startmap() applica una funzione agli elementi dell’iterabile passato ad essa. L’iterabile dovrebbe avere elementi raggruppati in tuple.

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

Produzione:

[13, 5, 9, 16, 11]

#11. prenditi un po’()

takewhile(funzione, iterable) funziona in modo opposto a dropwhile(). takewhile() accetta una funzione con una condizione da valutare e un iterabile. Include quindi tutti gli elementi nell’iterabile che soddisfano la condizione nella funzione finché non viene restituito False. Una volta restituito False, tutti i seguenti elementi nell’iterabile vengono ignorati.

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)

Produzione:

[1, 2, 3, 4]

#12. tee()

tee(iterable, n) accetta un iterabile e restituisce più iteratori indipendenti. Il numero di iteratori da restituire è impostato da n, che per impostazione predefinita è 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))

Produzione:

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

#13. zip_più lungo()

zip_longest(iterables, fillvalue) accetta più iteratori e un fillvalue. Quindi restituisce un iteratore che aggrega gli elementi di ciascuno degli iteratori che gli sono stati passati. Se gli iteratori non hanno la stessa lunghezza, i valori mancanti vengono sostituiti dal valore di riempimento passato alla funzione fino all’esaurimento dell’iterabile più lungo.

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)

Produzione:

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

Conclusione

Gli itertools Python sono un set di strumenti importante per uno sviluppatore Python. Gli itertool di Python sono ampiamente utilizzati nella programmazione funzionale, nell’elaborazione e nella trasformazione dei dati, nel filtraggio e nella selezione dei dati, nel raggruppamento e nell’aggregazione, combinando iterabili, combinatoria e quando si lavora con sequenze infinite.

In qualità di sviluppatore Python, trarrai grandi vantaggi dall’apprendimento di itertools, quindi assicurati di utilizzare questo articolo per familiarizzare con Python Itertools.