Вот версия, основанная на Карле, для которой не требуются копии списка (tmp
, фрагменты и сжатый список). izip
значительно быстрее, чем (Python 2) zip
для больших списков. chain
немного медленнее, чем нарезка, но не требует tmp
объекта или копий списка. islice
плюс создание tmp
немного быстрее, но требует больше памяти и менее элегантно.
from itertools import izip, chain
[y for x, y, z in izip(chain((None, None), li),
chain((None,), li),
li) if x != y != z]
Тест timeit
показывает, что он примерно в два раза быстрее, чем у Карла или моей самой быстрой версии groupby
для коротких групп.
Обязательно используйте значение, отличное от None
(например, object()
), если ваш список может содержать None
s.
Используйте эту версию, если она нужна для работы с итератором / итерируемым, который не является последовательностью, или если ваши группы длинные:
[key for key, group in groupby(li)
if (next(group) or True) and next(group, None) is None]
timeit
показывает, что примерно в десять раз быстрее, чем в другой версии для 1000 групп элементов.
Более ранние, медленные версии:
[key for key, group in groupby(li) if sum(1 for i in group) == 1]
[key for key, group in groupby(li) if len(tuple(group)) == 1]