Я бы использовал set
для запоминания увиденного и возврата из генератора, когда у вас достаточно seen
:
a = [1,2,2,3,3,4,5,6]
def get_unique_N(iterable, N):
"""Yields (in order) the first N unique elements of iterable.
Might yield less if data too short."""
seen = set()
for e in iterable:
if e in seen:
continue
seen.add(e)
yield e
if len(seen) == N:
return
k = get_unique_N([1,2,2,3,3,4,5,6], 4)
print(list(k))
Выход:
[1,2,3,4]
Согласно PEP-479 вы должны return
от генераторов, а не raise StopIteration
- спасибо @ khelwood & @ iBug за этот комментарий -никто никогда не узнает.
С 3.6 вы получаете устаревшее предупреждение, с 3.7 выдает RuntimeErrors: План перехода , если все еще используете raise StopIteration
Ваше решение с использованием elif element not in itr[:index] and count<upper:
используетO(k)
поисков - с k
длиной отрезка - использование набора уменьшает это до O(1)
поисков, но использует больше памяти, потому что набор также должен храниться.Это компромисс между скоростью и памятью - что лучше, зависит от приложения / данных.
Рассмотрим [1,2,3,4,4,4,4,5]
против [1]*1000+[2]*1000+[3]*1000+[4]*1000+[5]*1000+[6]
:
Для 6 уникальных номеров (в более длинном списке):
- у вас будет поиск
O(1)+O(2)+...+O(5001)
- у меня будет
5001*O(1)
поиск + память на set( {1,2,3,4,5,6})