2021-07-30 03:05:05 +02:00
|
|
|
from itertools import filterfalse
|
|
|
|
|
2021-11-24 08:51:37 +01:00
|
|
|
from typing import (
|
|
|
|
Callable,
|
|
|
|
Iterable,
|
|
|
|
Iterator,
|
|
|
|
Optional,
|
|
|
|
Set,
|
|
|
|
TypeVar,
|
|
|
|
Union,
|
|
|
|
)
|
2021-07-30 03:05:05 +02:00
|
|
|
|
2021-11-24 08:51:37 +01:00
|
|
|
# Type and type variable definitions
|
|
|
|
_T = TypeVar('_T')
|
|
|
|
_U = TypeVar('_U')
|
|
|
|
|
|
|
|
|
|
|
|
def unique_everseen(
|
|
|
|
iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = None
|
|
|
|
) -> Iterator[_T]:
|
2021-07-30 03:05:05 +02:00
|
|
|
"List unique elements, preserving order. Remember all elements ever seen."
|
|
|
|
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
|
|
|
|
# unique_everseen('ABBCcAD', str.lower) --> A B C D
|
2021-11-24 08:51:37 +01:00
|
|
|
seen: Set[Union[_T, _U]] = set()
|
2021-07-30 03:05:05 +02:00
|
|
|
seen_add = seen.add
|
|
|
|
if key is None:
|
|
|
|
for element in filterfalse(seen.__contains__, iterable):
|
|
|
|
seen_add(element)
|
|
|
|
yield element
|
|
|
|
else:
|
|
|
|
for element in iterable:
|
|
|
|
k = key(element)
|
|
|
|
if k not in seen:
|
|
|
|
seen_add(k)
|
|
|
|
yield element
|