Vad är Python Itertools-funktioner?

Modulen Itertools i Python erbjuder, enligt den officiella dokumentationen, en samling snabba och minnesoptimerade verktyg avsedda för att hantera iteratorer. Dessa verktyg kan användas individuellt eller i kombination, vilket ger en möjlighet att skapa och manipulera iteratorer på ett kortfattat, effektivt och resursmedvetet sätt.

Modulen Itertools innehåller en mängd funktioner som underlättar arbetet med iteratorer, speciellt när det handlar om stora datamängder. Genom att använda Itertools funktioner kan man bearbeta befintliga iteratorer och skapa mer komplexa iteratorer.

Användningen av Itertools bidrar till att minska antalet fel som kan uppstå vid arbete med iteratorer och hjälper utvecklare att skriva renare, mer lättläst och underhållbar kod.

Beroende på funktionen hos iteratorerna inom Itertools-modulen, kan de kategoriseras enligt följande:

#1. Oändliga iteratorer

Dessa iteratorer tillåter arbete med oändliga sekvenser, vilket gör att en loop kan fortsätta i all oändlighet om inget avbrottsvillkor definieras. Denna typ av iteratorer är användbar vid simulering av oändliga loopar eller generering av obegränsade sekvenser. Itertools innehåller tre oändliga iteratorer: count(), cycle() och repeat().

#2. Kombinatoriska iteratorer

Kombinatoriska iteratorer omfattar funktioner som möjliggör operationer på kartesiska produkter samt utför kombinationer och permutationer av element i en iterabel. Dessa funktioner är särskilt användbara när man behöver utforska alla möjliga sätt att ordna eller kombinera element. Itertools tillhandahåller fyra kombinatoriska iteratorer: product(), permutations(), combinations() och combinations_with_replacement().

#3. Iteratorer som avslutas vid den kortaste indatasekvensen

Dessa är avslutande iteratorer avsedda för ändliga sekvenser och genererar utdata baserat på den specifika funktionen som används. Exempel på avslutande iteratorer inkluderar: accumulate(), chain(), chain.from_iterable(), compress(), dropwhile(), filterfalse(), groupby(), islice(), pairwise(), starmap(), takewhile(), tee() och zip_longest().

Låt oss nu undersöka hur de olika funktionerna inom Itertools fungerar, baserat på deras kategorisering:

Oändliga iteratorer

De tre oändliga iteratorerna är:

#1. count()

Funktionen count(start, steg) skapar en oändlig sekvens av tal med start från värdet ’start’. Funktionen accepterar två valfria argument: ’start’ och ’steg’. Argumentet ’start’ bestämmer var sekvensen börjar. Om inget ’start’-värde anges börjar den som standard vid 0. Argumentet ’steg’ definierar skillnaden mellan varje efterföljande tal. Standardvärdet för ’steg’ är 1.

import itertools
# Räkna med start från 4, öka med 2
for i in itertools.count(4, 2):
    # Villkor för att avsluta loopen och undvika oändlig loopning
    if i == 14:
        break
    else:
        print(i) # utskrift - 4, 6, 8, 10, 12

Utskrift:

4
6
8
10
12

#2. cycle()

Funktionen cycle(iterable) tar en iterabel som argument och loopar sedan genom den iterablen, vilket ger tillgång till elementen i den ordning de visas.

Exempelvis, om vi skickar in [”röd”, ”grön”, ”gul”] till cycle(), kommer vi i den första loopen att ha tillgång till ”röd”; i den andra loopen ”grön” och därefter ”gul”. I den fjärde loopen, eftersom alla element i iterablen har passerats, börjar vi om från ”röd” och fortsätter oändligt.

När du anropar cycle(), spara resultatet i en variabel för att skapa en iterator som bibehåller sitt tillstånd. Detta säkerställer att loopen inte startar om varje gång och att du får tillgång till rätt element.

import itertools

färger = ["röd", "grön", "gul"]
# Skicka in färger till cycle()
färg_loop = itertools.cycle(färger)
print(färg_loop)

# Använd range() för att stoppa den oändliga loopen efter 7 utskrifter
# next() används för att hämta nästa element från iteratorn
for i in range(7):
    print(next(färg_loop))

Utskrift:

röd
grön
gul
röd
grön
gul
röd

#3. repeat()

Funktionen repeat(elem, n) tar två argument, ett element att upprepa (elem) och antalet gånger elementet ska upprepas (n). Elementet kan vara ett enkelt värde eller en iterabel. Om n inte anges kommer elementet att upprepas oändligt.

import itertools

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

Utskrift:

10
10
10

Kombinatoriska iteratorer

De kombinatoriska iteratorerna inkluderar:

#1. product()

Funktionen product() används för att beräkna den kartesiska produkten av den iterabel som skickas in. Om vi har två iterabler, till exempel x = {7, 8} och y = {1, 2, 3}, kommer den kartesiska produkten av x och y att innehålla alla möjliga kombinationer av element från x och y där det första elementet kommer från x och det andra från y. Den kartesiska produkten i det här fallet blir [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)].

Funktionen product() kan ta ett valfritt argument, repeat, som används för att beräkna den kartesiska produkten av en iterabel med sig själv. Argumentet repeat specificerar antalet repetitioner för varje element från de givna iterablerna vid beräkningen av den kartesiska produkten.

Till exempel, product(’ABCD’, repeat=2) ger kombinationer som (’A’, ’A’), (’A’, ’B’), (’A’, ’C’), och så vidare. Om repeat sattes till 3 skulle funktionen ge kombinationer som (’A’, ’A’, ’A’), (’A’, ’A’, ’B’), (’A’, ’A’, ’C’), (’A’, ’A’, ’D’) och så vidare.

from itertools import product
# product() med det valfria argumentet repeat
print("product() med det valfria argumentet repeat")
print(list(product('ABC', repeat = 2)))

# product() utan repeat
print("product() UTAN valfritt argumentet repeat")
print(list(product([7,8], [1,2,3])))

Utskrift:

product() med det valfria argumentet repeat
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
product() UTAN valfritt argumentet repeat
[(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]

#2. permutations()

Funktionen permutations(iterable, group_size) returnerar alla möjliga permutationer av iterablen som skickas in. En permutation representerar antalet sätt som element i en mängd kan ordnas. Funktionen kan ta ett valfritt argument group_size. Om group_size inte anges kommer de genererade permutationerna att ha samma storlek som iterablen som skickas till funktionen.

import itertools
nummer = [1, 2, 3]
storleks_permutationer = list(itertools.permutations(nummer,2))
ospec_permutationer = list(itertools.permutations(nummer))

print("Permutationer med en storlek av 2")
print(storleks_permutationer)
print("Permutationer UTAN storleksargument")
print(ospec_permutationer)

Utskrift:

Permutationer med en storlek av 2
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
Permutationer UTAN storleksargument
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

#3. combinations()

Funktionen combinations(iterable, storlek) returnerar alla möjliga kombinationer av en iterabel av given längd, från elementen i iterablen. Storleksargumentet anger storleken på varje kombination.

Resultaten är ordnade. Kombination skiljer sig från permutationer. Vid permutation spelar ordningen roll, men vid kombination spelar ordningen ingen roll. Till exempel, i [A, B, C] finns det 6 permutationer: AB, AC, BA, BC, CA, CB men endast 3 kombinationer: AB, AC, BC.

import itertools
nummer = [1, 2, 3, 4]
size2_kombination = list(itertools.combinations(nummer,2))
size3_kombination = list(itertools.combinations(nummer, 3))

print("Kombinationer med en storlek av 2")
print(size2_kombination)
print("Kombinationer med en storlek av 3")
print(size3_kombination)

Utskrift:

Kombinationer med en storlek av 2
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
Kombinationer med en storlek av 3
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]

#4. combinations_with_replacement()

Funktionen combinations_with_replacement(iterable, size) genererar alla möjliga kombinationer av en iterabel av en given längd, från den iterabel som skickas in, och tillåter att element upprepas i utdatakombinationerna. Storleken avgör storleken på de kombinationer som genereras.

Denna funktion skiljer sig från combinations() genom att den tillåter kombinationer där ett element kan upprepas mer än en gång. Till exempel kan man få en kombination som (1, 1) vilket inte är möjligt med combinations().

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

size2_kombination = list(itertools.combinations_with_replacement(nummer,2))
print("combinations_with_replacement => storlek 2")
print(size2_kombination)

Utskrift:

combinations_with_replacement => storlek 2
[(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]

Avslutande iteratorer

Dessa inkluderar iteratorer som:

#1. accumulate()

Funktionen accumulate(iterable, function) tar en iterabel och ett valfritt argument som är en funktion. Den returnerar sedan det ackumulerade resultatet av att applicera funktionen i varje iteration på elementen i iterablen. Om ingen funktion ges utförs addition och de ackumulerade resultaten returneras.

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

# Ackumulera summan av talen
ackumulerat_värde = itertools.accumulate(nummer)
ackumulerad_mult = itertools.accumulate(nummer, operator.mul)
print("Ackumulera utan funktion")
print(list(ackumulerat_värde))
print("Ackumulera med multiplikation")
print(list(ackumulerad_mult))

Utskrift:

Ackumulera utan funktion
[1, 3, 6, 10, 15]
Ackumulera med multiplikation
[1, 2, 6, 24, 120]

#2. chain()

Funktionen chain(iterable_1, iterable_2, …) tar flera iterabler och sammanfogar dem till en enda iterabel innehållande värden från de iterabler som skickas in till funktionen chain().

import itertools

bokstäver = ['A', 'B', 'C', 'D']
nummer = [1, 2, 3]
färger = ['röd', 'grön', 'gul']

# Sammanfoga bokstäver och nummer
sammanfogad_iterabel = list(itertools.chain(bokstäver, nummer, färger))
print(sammanfogad_iterabel)

Utskrift:

['A', 'B', 'C', 'D', 1, 2, 3, 'röd', 'grön', 'gul']

#3. chain.from_iterable()

Funktionen chain.from_iterable(iterable) liknar chain(). Skillnaden är att den endast tar en enda iterabel som innehåller sub-iterables och sammanfogar dem.

import itertools

bokstäver = ['A', 'B', 'C', 'D']
nummer = [1, 2, 3]
färger = ['röd', 'grön', 'gul']

iterabel = ['hej',färger, bokstäver, nummer]
kedja = list(itertools.chain.from_iterable(iterabel))
print(kedja)

Utskrift:

['h', 'e', 'j', 'röd', 'grön', 'gul', 'A', 'B', 'C', 'D', 1, 2, 3]

#4. compress()

Funktionen compress(data, selectors) tar in två argument: data, som är en iterabel, och selectors, som är en iterabel som innehåller booleska värden (true och false). 1 och 0 kan också användas som alternativ till de booleska värdena. compress() filtrerar sedan data baserat på motsvarande element i väljaren.

Värden i data som motsvarar värdet true eller 1 i väljaren väljs, medan de som motsvarar false eller 0 ignoreras. Om färre booleska värden skickas in i väljaren än antalet objekt i data kommer alla element efter de godkända booleska värdena i väljaren att ignoreras.

import itertools

# data innehåller 10 objekt
data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
# skickar in 9 väljarobjekt
väljare = [True, False, 1, False, 0, 1, True, False, 1]

# Välj element från data baserat på väljare
filtrerad_data = list(itertools.compress(data, väljare))
print(filtrerad_data)

Utskrift:

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

#5. dropwhile()

Funktionen dropwhile(funktion, sekvens) tar in en funktion med ett villkor som returnerar true eller false och en sekvens av värden. Den tappar sedan alla värden tills villkoret returnerar false. När villkoret returnerar false inkluderas resten av elementen i resultatet, oavsett om de skulle returnera true eller false.

import itertools

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

# Tappa element tills det givna villkoret returnerar False
filtrerade_nummer = list(itertools.dropwhile(lambda x: x < 5, nummer))
print(filtrerade_nummer)

Utskrift:

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

#6. filterfalse()

Funktionen filterfalse(funktion, sekvens) tar in en funktion med ett villkor som evalueras till true eller false och en sekvens. Den returnerar sedan värden från sekvensen som inte uppfyller villkoret i funktionen.

import itertools

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

# Filtrera element för vilka villkoret är False
filtrerade_nummer = list(itertools.filterfalse(lambda x: x < 4, nummer))
print(filtrerade_nummer)

Utskrift:

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

#7. groupby()

Funktionen groupby(iterable, key) tar in en iterabel och en nyckel och returnerar sedan en iterator som ger efterföljande nycklar och grupper. För att funktionen ska fungera korrekt måste den iterabel som skickas till den vara sorterad enligt samma nyckelfunktion. Nyckelfunktionen beräknar ett nyckelvärde för varje element i iterablen.

import itertools

input_lista = [("Inhemsk", "Ko"), ("Inhemsk", "Hund"), ("Inhemsk", "Katt"),("Vild", "Lejon"), ("Vild", "Zebra"), ("Vild", "Elefant")]
klassifikation = itertools.groupby(input_lista,lambda x: x[0])
for key,value in klassifikation:
    print(key,":",list(value))

Utskrift:

Inhemsk : [('Inhemsk', 'Ko'), ('Inhemsk', 'Hund'), ('Inhemsk', 'Katt')]
Vild : [('Vild', 'Lejon'), ('Vild', 'Zebra'), ('Vild', 'Elefant')]

#8. islice()

Funktionen islice(iterable, start, stop, step) låter dig segmentera en iterabel med hjälp av start-, stopp- och stegvärden. Stegargumentet är valfritt. Räkningen börjar från 0 och posten på stoppnumret ingår inte.

import itertools

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

# Välj element inom ett intervall
valda_nummer = list(itertools.islice(nummer, 2, 10))
valda_nummer_steg= list(itertools.islice(nummer, 2, 10,2))
print("islice utan stegvärde")
print(valda_nummer)
print("islice med ett stegvärde på 2")
print(valda_nummer_steg)

Utskrift:

islice utan stegvärde
[3, 4, 5, 6, 7, 8, 9, 10]
islice med ett stegvärde på 2
[3, 5, 7, 9]

#9. pairwise()

Funktionen pairwise(iterable) returnerar efterföljande överlappande par från den iterabel som skickas in, i den ordning de visas i iterabeln. Om iterablen innehåller färre än två värden, kommer resultatet från pairwise() att vara tomt.

from itertools import pairwise

nummer = [1, 2, 3, 4, 5, 6, 7, 8]
ord = 'VÄRLD'
enkel = ['A']

print(list(pairwise(nummer)))
print(list(pairwise(ord)))
print(list(pairwise(enkel)))

Utskrift:

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

#10. starmap()

Funktionen starmap(function, iterable) används istället för map() när argumentparametrarna redan är grupperade i tupler. startmap() tillämpar en funktion på elementen i iterablen som skickas in. Iterablen ska ha element grupperade i tupler.

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

Utskrift:

[13, 5, 9, 16, 11]

#11. takewhile()

Funktionen takewhile(funktion, iterable) fungerar på motsatt sätt som dropwhile(). takewhile() tar in en funktion med ett villkor som ska evalueras och en iterabel. Den inkluderar sedan alla element i iterabeln som uppfyller villkoret i funktionen tills False returneras. När False returneras ignoreras alla följande element i iterablen.

import itertools

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

# Inkludera element tills det givna villkoret är False
filtrerade_nummer = list(itertools.takewhile(lambda x: x < 5, nummer))
print(filtrerade_nummer)

Utskrift:

[1, 2, 3, 4]

#12. tee()

Funktionen tee(iterable, n) tar in en iterabel och returnerar flera oberoende iteratorer. Antalet iteratorer som ska returneras bestäms av n, som som standard är 2.

import itertools

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

# Skapa två oberoende iteratorer från nummer
iter1, iter2 = itertools.tee(nummer, 2)
print(list(iter1))
print(list(iter2))

Utskrift:

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

#13. zip_longest()

Funktionen zip_longest(iterables, fillvalue) tar in flera iteratorer och ett fillvalue. Den returnerar sedan en iterator som sammanför element från var och en av de iteratorer som skickas in. Om iteratorerna inte är av samma längd ersätts de saknade värdena med fyllningsvärdet (fillvalue) tills den längsta iterablen är förbrukad.

import itertools

namn = ['John', 'Mathew', 'Mary', 'Alice', 'Bob', 'Charlie', 'Fury']
åldrar = [25, 30, 12, 13, 42]

# Kombinera namn och åldrar, fyll i saknade åldrar med ett bindestreck
kombinerat = itertools.zip_longest(namn, åldrar, fillvalue="-")

for namn, ålder in kombinerat:
    print(namn, ålder)

Utskrift:

John 25
Mathew 30
Mary 12
Alice 13
Bob 42
Charlie -
Fury -

Slutsats

Python itertools är en viktig verktygslåda för en Python-utvecklare. Modulen används i stor utsträckning inom funktionell programmering, databehandling och -transformation, datafiltrering och -urval, gruppering och aggregering, kombination av iterabler, kombinatorik samt vid arbete med oändliga sekvenser.

Som Python-utvecklare kommer du att ha stor nytta av att bekanta dig med itertools, så använd den här artikeln som en guide för att fördjupa dina kunskaper.