Счетчик разрешающих повторений
У меня есть светофор Enum, определяющий возможные состояния:
class TrafficLightPhase(Enum):
RED = "RED"
YELLOW = "YELLOW"
GREEN = "GREEN"
Я опрашиваю светофор, чтобы узнать текущее состояние каждую секунду, и помещаю значения в deque
с этой функцией:
def read_phases():
while running:
current_phase = get_current_phase_phases()
last_phases.append(current_phase)
time.sleep(1)
Я хочу сгруппировать последовательности одного и того же состояния, чтобы узнать время фаз светофора.
Я пытался использовать Counter
класс collections
, как это:
counter = collections.Counter(last_phases)
Он очень хорошо группирует разные состояния, но я не знаю, когда начнется следующий цикл. Есть ли подобная структура данных, как Counter
что позволяет повторений? так что я могу получить результаты, такие как:
Counter({
'RED': 10,
'GREEN': 10,
'YELLOW': 3,
'RED': 10,
'GREEN': 10,
'YELLOW': 3,
'RED': 10,
'GREEN': 10,
'YELLOW': 3
})
вместо: Счетчик ({"КРАСНЫЙ": 30, "ЗЕЛЕНЫЙ": 30, "ЖЕЛТЫЙ": 9 })
2 ответа
Я хотел бы использовать itertools.groupby
за это. Он сгруппирует смежные серии одного и того же элемента, после чего вы сможете проверить длину каждого цикла.
>>> from itertools import groupby
>>> last_phases= ['red', 'red', 'yellow', 'red', 'red', 'green']
>>> [(key, len(list(group))) for key,group in groupby(last_phases)]
[('red', 2), ('yellow', 1), ('red', 2), ('green', 1)]
collections.Counter
здесь не сработает, так как не различает элементы по порядку.
Я рекомендую вам использовать itertools.groupby
,
Но, для справки, ниже приведено решение, использующее collections.defaultdict
,
from collections import defaultdict
from itertools import islice, chain, zip_longest
d = defaultdict(lambda: defaultdict(int))
last_phases= ['red', 'red', 'yellow', 'red', 'red', 'green']
c = 0
for i, j in zip_longest(last_phases, islice(last_phases, 1, None)):
d[c][i] += 1
if i != j:
c += 1
res = list(chain.from_iterable(i.items() for i in d.values()))
[('red', 2), ('yellow', 1), ('red', 2), ('green', 1)]