Python Language
Itertools Module
Zoeken…
Syntaxis
import itertools
Items van een iterabel object groeperen met een functie
Begin met een iterabele die moet worden gegroepeerd
lst = [("a", 5, 6), ("b", 2, 4), ("a", 2, 5), ("c", 2, 6)]
Genereer de gegroepeerde generator, gegroepeerd op het tweede element in elke tuple:
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)]
Alleen groepen opeenvolgende elementen worden gegroepeerd. Mogelijk moet u op dezelfde toets sorteren voordat u groupby oproept. Bijvoorbeeld: (laatste element is gewijzigd)
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)]
De groep die wordt geretourneerd door groupby is een iterator die ongeldig is vóór de volgende iteratie. Het volgende werkt bijvoorbeeld niet als u wilt dat de groepen op sleutel worden gesorteerd. Groep 5 is hieronder leeg, omdat wanneer groep 2 wordt opgehaald 5 ongeldig wordt
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 []
Om correct te sorteren, maak een lijst van de iterator voordat u sorteert
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)]
Neem een plakje generator
Met Itertools "islice" kunt u een generator snijden:
results = fetch_paged_results() # returns a generator
limit = 20 # Only want the first 20 results
for data in itertools.islice(results, limit):
print(data)
Normaal gesproken kun je een generator niet segmenteren:
def gen():
n = 0
while n < 20:
n += 1
yield n
for part in gen()[:3]:
print(part)
Zullen geven
Traceback (most recent call last):
File "gen.py", line 6, in <module>
for part in gen()[:3]:
TypeError: 'generator' object is not subscriptable
Dit werkt echter:
import itertools
def gen():
n = 0
while n < 20:
n += 1
yield n
for part in itertools.islice(gen(), 3):
print(part)
Merk op dat als een normale snee, dan kunt u ook gebruik maken van start
, stop
en step
argumenten:
itertools.islice(iterable, 1, 30, 3)
itertools.product
Met deze functie kunt u het Cartesiaanse product van een lijst met iterables herhalen.
Bijvoorbeeld,
for x, y in itertools.product(xrange(10), xrange(10)):
print x, y
is gelijk aan
for x in xrange(10):
for y in xrange(10):
print x, y
Zoals alle python-functies die een variabel aantal argumenten accepteren, kunnen we een lijst doorgeven aan itertools.product voor uitpakken, met de operator *.
Dus,
its = [xrange(10)] * 2
for x,y in itertools.product(*its):
print x, y
produceert dezelfde resultaten als beide voorgaande voorbeelden.
>>> 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
Invoering:
Deze eenvoudige functie genereert een oneindige reeks getallen. Bijvoorbeeld...
for number in itertools.count():
if number > 20:
break
print(number)
Merk op dat we moeten breken, anders wordt het voor altijd afgedrukt!
Output:
0
1
2
3
4
5
6
7
8
9
10
argumenten:
count()
neemt twee argumenten, start
en step
:
for number in itertools.count(start=10, step=4):
print(number)
if number > 20:
break
Output:
10
14
18
22
itertools.takewhile
itertools.takewhile stelt u in staat om items uit een reeks te nemen totdat een voorwaarde eerst 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)
Dit voert [0, 2, 4, 12, 18]
.
Merk op dat het eerste getal dat het predicaat schendt (dwz: de functie die een Booleaanse waarde retourneert) is_even
is, 13
. Zodra takewhile
een waarde tegenkomt die False
produceert voor het gegeven predicaat, breekt het uit.
De output geproduceerd door takewhile
is vergelijkbaar met de output gegenereerd door de onderstaande code.
def takewhile(predicate, iterable):
for x in iterable:
if predicate(x):
yield x
else:
break
Opmerking: De samenvoeging van resultaten die zijn geproduceerd door takewhile
en dropwhile
levert de oorspronkelijke iterabele op.
result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))
itertools.dropwhile
Met itertools.dropwhile kunt u items uit een reeks nemen nadat een voorwaarde eerst 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)
Dit voert [13, 14, 22, 23, 44]
.
( Dit voorbeeld is hetzelfde als het voorbeeld voor takewhile
maar met dropwhile
. )
Merk op dat het eerste getal dat het predicaat schendt (dwz: de functie die een Booleaanse waarde retourneert) is_even
is, 13
. Alle elementen daarvoor worden weggegooid.
De output geproduceerd door dropwhile
is vergelijkbaar met de output gegenereerd door de onderstaande code.
def dropwhile(predicate, iterable):
iterable = iter(iterable)
for x in iterable:
if not predicate(x):
yield x
break
for x in iterable:
yield x
De samenvoeging van resultaten geproduceerd door takewhile
en dropwhile
produceert de originele iterabele.
result = list(itertools.takewhile(is_even, lst)) + list(itertools.dropwhile(is_even, lst))
Ritsen van twee iterators totdat ze allebei uitgeput zijn
Net als bij de ingebouwde functie zip()
, zal itertools.zip_longest
doorgaan met itereren voorbij het einde van de kortere van twee 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)
Een optioneel fillvalue
argument kan als volgt worden doorgegeven (standaard ingesteld op ''
):
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)
In Python 2.6 en 2.7 wordt deze functie itertools.izip_longest
.
Combinatiemethode in Itertools Module
itertools.combinations
retourneert een generator van de k -combinatiesequentie van een lijst.
Met andere woorden: het retourneert een generator van tupels van alle mogelijke k-gewijs combinaties van de invoerlijst.
Bijvoorbeeld:
Als u een lijst hebt:
a = [1,2,3,4,5]
b = list(itertools.combinations(a, 2))
print b
Output:
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
De bovenstaande uitvoer is een generator omgezet in een lijst met tupels van alle mogelijke paren- combinaties van de invoerlijst a
Je kunt ook alle 3-combinaties vinden:
a = [1,2,3,4,5]
b = list(itertools.combinations(a, 3))
print b
Output:
[(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)]
Meerdere iterators aan elkaar koppelen
Gebruik itertools.chain
om een enkele generator te maken die de waarden van verschillende generators achter elkaar oplevert.
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))
Resulteert in:
'1 2 3 4 x y z'
Als alternatieve constructor kunt u de classmethod chain.from_iterable
die als zijn enige parameter een iterabele iterables neemt. Om hetzelfde resultaat te krijgen als hierboven:
' '.join(chain.from_iterable([a,b])
Hoewel chain
een willekeurig aantal argumenten kan chain.from_iterable
is chain.from_iterable
de enige manier om een oneindig aantal iterables te koppelen.
itertools.repeat
Herhaal iets n keer:
>>> import itertools
>>> for i in itertools.repeat('over-and-over', 3):
... print(i)
over-and-over
over-and-over
over-and-over
Krijg een verzamelde som van getallen in een iterabel
accumulate
levert een cumulatieve som (of product) van getallen op.
>>> 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]
Doorloop elementen in een iterator
cycle
is een oneindige iterator.
>>> import itertools as it
>>> it.cycle('ABCD')
A B C D A B C D A B C D ...
Zorg er daarom voor dat u grenzen geeft wanneer u dit gebruikt om een oneindige lus te voorkomen. Voorbeeld:
>>> # 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
retourneert een generator met opeenvolgende r-lengte permutaties van elementen in het iterabele.
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)]
als de lijst a
dubbele elementen heeft, zullen de resulterende permutaties dubbele elementen hebben, u kunt set
gebruiken om unieke permutaties te krijgen:
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)}