刪除序列相同元素并保持順序
問題
在序列上保持元素順序的同時刪除重復的值
解決
>>> def dedup(items):
... seen = set()
... for item in items:
... if item not in seen:
... seen.add(item)
... return seen
...
>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(dedup(a))
[1, 2, 5, 9, 10]
首先看錯誤的渠啤,上面代碼雖然完成了去重泊柬,但是元素的位置發(fā)生了變化
下面是正確代碼
>>> def dedup(items):
... seen = set()
... for item in items:
... if item not in seen:
... yield item
... seen.add(item)
...
>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(dedup(a))
[1, 5, 2, 9, 10]
這里的方法僅適用于元素是可哈希的,而yield
的作用就是返回迭代器打毛。
可以將上面的函數改造一下看一下結果
def dedup(items):
seen = set()
for item in items:
if item not in seen:
yield item
seen.add(item)
print('a')
>>> list(dedup(a))
a
a
a
a
a
[1, 5, 2, 9, 10]
因為dedup
函數帶yield
,所以它返回的是一個迭代器,我們可以用next()
函數狈醉,分步運行便于理解
>>> c = dedup(a)
>>> next(c)
1
>>> next(c)
a
5
>>> next(c)
a
2
>>> next(c)
a
9
>>> next(c)
a
10
c
是一個迭代器,調用next()
發(fā)現(xiàn)惠险,每一次的函數運行只進行到yield
字段苗傅,yield
后面的在下次函數調用中完成。
如果想消除元素不可哈希的序列中的重復元素(比如字典)班巩,需要把代碼再改一下
>>> def dedup(items, key = None):
... seen = set()
... for item in items:
... val = item if key is None else key(item)
... if val not in seen:
... yield item
... seen.add(val)
...
a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
>>> list(dedup(a, key=lambda d: (d['x'],d['y'])))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]