Вам необходимо использовать хеш-таблицу (также известную как отображения или словари) для отслеживания подписок и отписок, где ключом является идентификатор действия. Хеш-таблицы дают O (1) постоянный поиск времени, поэтому тестирование, чтобы увидеть, был ли обработан идентификатор действия до того, дешево. В Python тип dict
является такой хеш-таблицей. С помощью хеш-таблицы вы можете обработать ваши действия за O (N) времени за N действий, то есть за линейное время.
Использование списка Python, с другой стороны, неэффективно, поскольку списки (массивы, последовательности) требуют полного сканирования для проверки членства. Это означает, что они тратят O (N) времени, чтобы проверить, был ли идентификатор действия уже виден ранее, и ваш алгоритм замедляется по мере добавления новых действий, а ваш код выполняет O (N ^ 2) (N раз N) шагов для обработки все N действий. Поскольку ваш список действий увеличивается в размере, его обработка занимает квадратичное время.
Дополнительным преимуществом хеш-таблицы является то, что действия, которые перечислены только для подписки или отмены подписки (а не обоих), дублируются. Действие Если в списке будет подписано дважды, подписка будет только один раз.
Итак, чтобы реализовать это в Python, используйте тип dict
. Чтобы упростить тестирование, если идентификатор действия уже обработан для напротив изменения , вы создаете кортеж с двумя словарями . Эти подписки карты и отписки от подписки. К кортежу обращаются по индексу для «отписаться» (0
) и «подписаться» (1
), и вы можете тривиально откорректировать этот индекс, чтобы посмотреть в «противоположный» сегмент, вычитая из 1. Так что если действие А подписавшись (индекс 1), вы регистрируете 1 - 1
> item 0
в кортеже и наоборот.
Я предполагаю, что action.change
- это строковое значение, установленное в 'subscribe'
или 'unsubscribe'
, и эту строку можно использовать для сопоставления с индексами с дополнительным словарем:
changes = ({}, {}) # unsub, sub
changemap = {'unsubscribe': 0, 'subscribe': 1}
for action in action_list:
change = changemap[action.change] # unsubscribe / subscribe -> 0 or 1
if action.id_ in changes[1 - change]: # 0 becomes 1, 1 becomes 0
# action is listed twice for both subscribe and unsubscribe
# cancel opposite and skip this action
del changes[1 - change][action.id_]
continue
changes[change][action.id_] = action
Теперь у вас есть два словаря с отписками и подписками, которые можно обрабатывать отдельно:
for action in changes[0].values():
# unsubscribe action
for action in changes[1].values():
# subscribe action
Если вы используете Python 3.6 или новее, словари производят свои ключи и значения в порядке вставки, поэтому вышеописанное будет обрабатывать все отписки в том же относительном порядке, в котором они были перечислены в actions_list
, и то же самое относится к подпискам.
Если вам только нужен атрибут action.id_
для подписки или отмены подписки на действие, вы можете заменить словари наборами и сохранить только идентификаторы действий. Наборы не помнят порядок вставки, однако.
Если действия должны быть отброшены в целом , если они перечислены как минимум два раза с конфликтующими изменениями (например, две подписки и одна отмена подписки), то вам также нужен отдельный набор "отмена", отслеживающий удаленные вами идентификаторы от рассмотрения:
changes = ({}, {}) # unsub, sub
changemap = {'unsubscribe': 0, 'subscribe': 1}
cancelled = set()
for action in action_list:
if action.id_ in cancelled:
# this action.id_ has been observed to both subscribe and unsubscribe
# and has been cancelled altogether.
continue
change = changemap[action.change] # unsubscribe / subscribe -> 0 or 1)
if action.id_ in changes[1 - change]:
# action is listed twice for both subscribe and unsubscribe
# cancel opposite and ignore all further references to this action id
del changes[1 - change][action.id_]
cancelled.add(action.id_)
continue
changes[change][action.id_] = action