Как превратить объект itertools "grouper" в список

Я пытаюсь научиться использовать itertools.groupby в Python, и я хотел найти размер каждой группы символов. Сначала я попытался найти длину одной группы:--3-->

from itertools import groupby
len(list(list( groupby("cccccaaaaatttttsssssss") )[0][1]))

и я бы получал 0 каждый раз.

Я провел небольшое исследование и обнаружил, что другие люди делают это таким образом:

from itertools import groupby
for key,grouper in groupby("cccccaaaaatttttsssssss"):
    print key,len(list(grouper))

, который работает отлично. Что меня смущает, так это почему последний код работает, а первый-нет? Если бы я хотел чтобы получить только N-ю группу, как я пытался сделать в своем исходном коде, как бы я это сделал?

1 ответов


причина, по которой ваш первый подход не работает, заключается в том, что группы "потребляются" при создании этого списка с

list(groupby("cccccaaaaatttttsssssss"))

цитата из на groupby docs

возвращаемая группа сама по себе является итератором, который разделяет базовый итерируемым с groupby(). Потому что источник является общим, когда groupby() объект расширен, предыдущая группа больше не является видимый.

давайте разобьем его на этапы.

from itertools import groupby

a = list(groupby("cccccaaaaatttttsssssss"))
print(a)
b = a[0][1]
print(b)
print('So far, so good')
print(list(b))
print('What?!')

выход

[('c', <itertools._grouper object at 0xb715104c>), ('a', <itertools._grouper object at 0xb715108c>), ('t', <itertools._grouper object at 0xb71510cc>), ('s', <itertools._grouper object at 0xb715110c>)]
<itertools._grouper object at 0xb715104c>
So far, so good
[]
What?!

наши itertools._grouper object at 0xb715104c пуст, потому что он разделяет его содержимое с "родительским" итератором, возвращаемым groupby, и эти предметы теперь исчезли, потому что это первое list вызов повторяется над родителем.

это действительно не отличается от того, что происходит, если вы пытаетесь повторить дважды над любым итератором, например, простым генератором выражение.

g = (c for c in 'python')
print(list(g))
print(list(g))

выход

['p', 'y', 't', 'h', 'o', 'n']
[]

кстати, вот еще один способ получить длину groupby group, Если вам на самом деле не нужно его содержимое; это немного дешевле (и использует меньше ОЗУ), чем создание списка, чтобы найти его длину.

from itertools import groupby

for k, g in groupby("cccccaaaaatttttsssssss"):
    print(k, sum(1 for _ in g))

выход

c 5
a 5
t 5
s 7