Модуль itertools

Введение

Примеры

Группировка элементов из повторяемого объекта с помощью функции

Начните с итерации, которую нужно сгруппировать

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

 

Генерация сгруппированного генератора, группировка по второму элементу в каждом кортеже:

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

 

Только группы последовательных элементов сгруппированы. Возможно, вам придется отсортировать по одному и тому же ключу перед вызовом groupby. Например, (последний элемент изменен)

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

 

Группа, возвращаемая groupby, является итератором, который будет недействительным до следующей итерации. Например, следующее не будет работать, если вы хотите, чтобы группы сортировались по ключу. Группа 5 пуста ниже, потому что, когда группа 2 выбирается, она делает недействительным 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 []

 

Чтобы правильно выполнить сортировку, создайте список из итератора перед сортировкой

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

Возьми кусочек генератора

Itertools "islice" позволяет нарезать генератор:

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

 

Обычно вы не можете нарезать генератор:

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

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

 

Дам

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

 

Тем не менее, это работает:

 import itertools

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

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

 

Обратите внимание , что как обычный ломтик, вы также можете использовать start , stop и step аргументы:

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

itertools.product

Эта функция позволяет перебирать декартово произведение списка итераций.

Например,

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

 

эквивалентно

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

 

Как и все функции Python, которые принимают переменное число аргументов, мы можем передать список распаковке в itertools.product с помощью оператора *.

Таким образом,

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

 

дает те же результаты, что и оба предыдущих примера.

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

Вступление:

Эта простая функция генерирует бесконечные серии чисел. Например...

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

 

Обратите внимание, что мы должны сломаться, или это печатает навсегда!

Выход:

 0
1
2
3
4
5
6
7
8
9
10

 

Аргументы:

count() - start step count() принимает два аргумента, start и step :

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

 

Выход:

 10
14
18
22 

itertools.takewhile

itertools.takewhile позволяет принимать элементы из последовательности , пока условие не станет первым 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) 

Эти выходы [0, 2, 4, 12, 18] .

Отметим, что первое число , которое нарушает предикат (т.е. функция возвращает логическое значение) is_even есть, 13.После того, как takewhile встречает значение , которое производит False для данного предиката, он вспыхивает.

Выход производства takewhile похож на выходе генерируется из кода ниже.

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

Примечание: конкатенация результатов , полученных takewhile и dropwhile производит оригинальную Iterable.

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

itertools.dropwhile

itertools.dropwhile позволяет принимать элементы из последовательности после того, как условие первого становится 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) 

Эти выходы [13, 14, 22, 23, 44] .

( В этом примере такой же , как пример для takewhile , но с использованием dropwhile .)

Отметим, что первое число , которое нарушает предикат (т.е. функция возвращает логическое значение) is_even есть, 13.Все элементы до этого отбрасываются.

Выход производства dropwhile похож на выходе генерируется из кода ниже.

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

Конкатенация результатов , полученных takewhile и dropwhile производит оригинальную Iterable.

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

Молнии двух итераторов, пока они не исчерпаны

Подобно встроенной функции zip() , itertools.zip_longest будет продолжать итерации после окончания короче двух итерируемых.

 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)

 

Необязательный fillvalue аргумент может быть передан ( по умолчанию '' ) , так как:

 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)

 

В Python 2.6 и 2.7, эта функция называется itertools.izip_longest .

Метод комбинаций в модуле Itertools

itertools.combinations возвращает генератор последовательности к -combination списка.

Другими словами: он будет возвращать генератор кортежей всех возможных K-накрест комбинаций входного списка.

Например:

Если у вас есть список:

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

 

Выход:

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

Выше выход генератора преобразуется в список кортежей из всех возможных комбинаций пары -wise списка входных a

Вы также можете найти все 3 комбинации:

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

 

Выход:

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

Объединение нескольких итераторов в цепочку

Используйте itertools.chain , чтобы создать единый генератор , который позволит получить значения из нескольких генераторов в последовательности.

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

 

Результаты в:

 '1 2 3 4 x y z'

 

В качестве альтернативного конструктора, вы можете использовать Метод класс chain.from_iterable , который принимает в качестве единственного параметра итератора из итерируемых. Чтобы получить тот же результат, что и выше:

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

 

В то время как chain может принимать произвольное число аргументов, chain.from_iterable это единственный путь к цепи бесконечного числа итерируемых.

itertools.repeat

Повторите что-нибудь n раз:

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

Получить накопленную сумму чисел в итерируемом

`Накапливать` дает кумулятивную сумму (или произведение) чисел. >>> импортировать itertools как есть >>> оператор импорта >>> 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]

Перебирать элементы в итераторе

cycle представляет собой бесконечный итератор.

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

 

Поэтому при использовании этого параметра старайтесь не создавать бесконечный цикл. Пример:

 >>> # 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 возвращает генератор с последовательными г длиной перестановками элементов в итерации.

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

 

если список содержит повторяющиеся элементы, полученные в результате перестановки будут иметь повторяющиеся элементы, вы можете использовать a set , чтобы получить уникальные перестановки:

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

Синтаксис

Параметры

Примечания