Sök…


Syntax

  • import itertools

Gruppera objekt från ett iterable objekt med en funktion

Börja med en iterable som måste grupperas

lst = [("a", 5, 6), ("b", 2, 4), ("a", 2, 5), ("c", 2, 6)]

Generera den grupperade generatorn, gruppera efter det andra elementet i varje tupel:

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

Endast grupper av på varandra följande element grupperas. Du kanske måste sortera efter samma tangent innan du ringer gruppby för t.ex. (Sista element ändras)

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

Gruppen som returneras av groupby är en iterator som kommer att vara ogiltig före nästa iteration. Exempelvis fungerar inte följande om du vill att grupperna ska sorteras efter nyckel. Grupp 5 är tom nedan eftersom när grupp 2 hämtas ogiltigför den 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 []

För att sortera korrekt ska du skapa en lista från iteratorn innan du sorterar

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

Ta en skiva av en generator

Itertools "islice" låter dig skära en generator:

results = fetch_paged_results()  # returns a generator
limit = 20  # Only want the first 20 results
for data in itertools.islice(results, limit):
    print(data)

Normalt kan du inte skära en generator:

def gen():
    n = 0
    while n < 20:
        n += 1
        yield n

for part in gen()[:3]:
    print(part)

Kommer att ge

Traceback (most recent call last):
  File "gen.py", line 6, in <module>
    for part in gen()[:3]:
TypeError: 'generator' object is not subscriptable

Men detta fungerar:

import itertools

def gen():
    n = 0
    while n < 20:
        n += 1
        yield n

for part in itertools.islice(gen(), 3):
    print(part)

Observera att som en vanlig skiva, kan du också använda start , stop och step argument:

itertools.islice(iterable, 1, 30, 3)

itertools.product

Denna funktion låter dig iterera över den kartesiska produkten av en lista med iterables.

Till exempel,

for x, y in itertools.product(xrange(10), xrange(10)):
    print x, y

är ekvivalent med

for x in xrange(10):
    for y in xrange(10):
        print x, y

Liksom alla pythonfunktioner som accepterar ett variabelt antal argument, kan vi skicka en lista till itertools.product för packning, med * -operatören.

Således,

its = [xrange(10)] * 2
for x,y in itertools.product(*its):
    print x, y

ger samma resultat som båda de tidigare exemplen.

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

Introduktion:

Denna enkla funktion genererar oändliga antal serier. Till exempel...

for number in itertools.count():
    if number > 20:
        break
    print(number)

Observera att vi måste bryta eller så skrivs det ut för alltid!

Produktion:

0
1
2
3
4
5
6
7
8
9
10

Argument:

count() tar två argument, start och step :

for number in itertools.count(start=10, step=4):
    print(number)
    if number > 20:
        break

Produktion:

10
14
18
22

itertools.takewhile

itertools.takewhile gör att du kan ta objekt från en sekvens tills ett tillstånd först blir 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)
  

Denna utgångar [0, 2, 4, 12, 18] .

Observera att det första numret som bryter mot predikatet (dvs. funktionen som returnerar ett booleskt värde) is_even är 13 . När takewhile möter ett värde som producerar False för det givna predikatet, bryter det ut.

Utgången som produceras av takewhile liknar den som produceras från koden nedan.

def takewhile(predicate, iterable):
    for x in iterable:
        if predicate(x):
            yield x
        else:
            break

Obs: Sammanlänkningen av resultat som produceras av takewhile och dropwhile ger den ursprungliga iterable.

result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))

itertools.dropwhile

itertools.dropetime gör att du kan ta objekt från en sekvens efter att ett tillstånd först blev 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)
  

Denna utgångar [13, 14, 22, 23, 44] .

(Det här exemplet är samma som exemplet för takewhile men använder dropwhile . )

Observera att det första numret som bryter mot predikatet (dvs. funktionen som returnerar ett booleskt värde) is_even är 13 . Alla element innan detta kasseras.

Utgången som produceras efter dropwhile liknar den som genereras från koden nedan.

def dropwhile(predicate, iterable):
    iterable = iter(iterable)
    for x in iterable:
        if not predicate(x):
            yield x
            break
    for x in iterable:
        yield x

Sammankopplingen av resultat som produceras av takewhile och dropwhile ger den ursprungliga iterable.

result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))

Dragkedja två iteratorer tills de båda är utmattade

I likhet med den inbyggda funktionen zip() kommer itertools.zip_longest att fortsätta att iterera bortom slutet av den kortare av två 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)

Ett valfritt fillvalue kan skickas (som standard till '' ) så:

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)

I Python 2.6 och 2.7 kallas den här funktionen itertools.izip_longest .

Kombinationsmetod i Itertools-modulen

itertools.combinations kommer att returnera en generator med k- kombinationssekvensen i en lista.

Med andra ord: Det kommer att returnera en generator med tuplar med alla möjliga k-kloka kombinationer av inmatningslistan.

Till exempel:

Om du har en lista:

a = [1,2,3,4,5]
b = list(itertools.combinations(a, 2))
print b

Produktion:

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

Ovanstående utgång är en generator omvandlas till en lista med tupler av alla de möjliga par -wise kombinationer av ingångslistan a

Du kan också hitta alla 3-kombinationer:

a = [1,2,3,4,5]
b = list(itertools.combinations(a, 3))
print b

Produktion:

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

Kedja flera iteratorer ihop

Använd itertools.chain att skapa en enda generator som ger värden från flera generatorer i följd.

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

Resulterar i:

'1 2 3 4 x y z'

Som en alternativ konstruktör kan du använda klassmetoden chain.from_iterable som tar sin enda parameter som en iterable av iterables. För att få samma resultat som ovan:

' '.join(chain.from_iterable([a,b])

Medan chain kan ta ett godtyckligt antal argument, är chain.from_iterable det enda sättet att kedja ett oändligt antal iterables.

itertools.repeat

Upprepa något n gånger:

>>> import itertools
>>> for i in itertools.repeat('over-and-over', 3):
...    print(i)
over-and-over
over-and-over
over-and-over

Få en ackumulerad summa av siffror i en iterable

Python 3.x 3.2

accumulate ger en kumulativ summa (eller produkt) av siffror.

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

Bläddra igenom element i en iterator

cycle är en oändlig iterator.

>>> import itertools as it
>>> it.cycle('ABCD')
A B C D A B C D A B C D ...

Var därför noga med att ge gränser när du använder detta för att undvika en oändlig slinga. Exempel:

>>> # 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.permutations

itertools.permutations returnerar en generator med successiva r-längd permutationer av element i det 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)]

om listan a har duplicerade element, kommer de resulterande permutationerna att ha duplikatelement, kan du använda set att få unika permutationer:

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow