--- a/src/pyams_utils/list.py Thu Jun 28 08:35:02 2018 +0200
+++ b/src/pyams_utils/list.py Fri Jun 29 18:15:51 2018 +0200
@@ -14,13 +14,14 @@
# import standard library
+from itertools import filterfalse
# import interfaces
# import packages
-def unique(seq, idfun=None):
+def unique(seq, key=None):
"""Extract unique values from list, preserving order
:param iterator seq: input list
@@ -41,17 +42,41 @@
You can also set an 'id' function applied on each element:
>>> mylist = [1, 2, 3, '2', 4]
- >>> unique(mylist, idfun=str)
+ >>> unique(mylist, key=str)
[1, 2, 3, 4]
+ >>> mylist = ['A', 'B', 'b', '2', 4]
+ >>> unique(mylist, key=lambda x: str(x).lower())
+ ['A', 'B', '2', 4]
"""
- if idfun is None:
- def idfun(x): return x
- seen = {}
+ seen = set()
+ seen_add = seen.add
result = []
- for item in seq:
- marker = idfun(item)
- if marker in seen:
- continue
- seen[marker] = 1
- result.append(item)
+ if key is None:
+ for element in filterfalse(seen.__contains__, seq):
+ seen_add(element)
+ result.append(element)
+ else:
+ for element in seq:
+ k = key(element)
+ if k not in seen:
+ seen_add(k)
+ result.append(element)
return result
+
+
+def unique_iter(iterable, key=None):
+ """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
+ seen = set()
+ 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