| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | from itertools import filterfalse | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-24 02:51:37 -05:00
										 |  |  | from typing import ( | 
					
						
							|  |  |  |     Callable, | 
					
						
							|  |  |  |     Iterable, | 
					
						
							|  |  |  |     Iterator, | 
					
						
							|  |  |  |     Optional, | 
					
						
							|  |  |  |     Set, | 
					
						
							|  |  |  |     TypeVar, | 
					
						
							|  |  |  |     Union, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-24 02:51:37 -05: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-29 21:05:05 -04: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 02:51:37 -05:00
										 |  |  |     seen: Set[Union[_T, _U]] = set() | 
					
						
							| 
									
										
										
										
											2021-07-29 21:05:05 -04: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 |