【Python 秘籍】从序列中移除重复项且保持元素间顺序不变
问题
我们想去除序列中出现的重复元素,但仍然保持剩下的元素顺序不变。
解决方案
这个问题可以通过使用列表和生成器轻松解决。示例如下:
def dedupe(items):
seen = []
for item in items:
if item not in seen:
yield item
seen.append(item)
下面是如何使用这个函数的例子:
>>> a = [1, 5, 2, 1, 9, 1, 5, 10]
>>> list(dedupe(a))
[1, 5, 2, 9, 10]
>>> b = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
>>> list(dedupe(b))
[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
对于以上序列元素为不可哈希对象的例子中,如果我们只想看元素中的某个键是否重复,可以对上述代码稍作修改:
def dedupe(items, key=None):
seen = []
for item in items:
val = item if not key else key(item)
if val not in seen:
yield item
seen.append(val)
相应的用法如下:
>>> list(dedupe(b, key=lambda d: d['x']))
[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
讨论
如果想要做的只是去除重复项,那么通常足够简单的办法就是构建一个集合。例如:
>>> a
[1, 5, 2, 1, 9, 1, 5, 10]
>>> set(a)
[1, 2, 5, 9, 10]
但是这种方法不能保证元素间的顺序不变(因为集合是无序容器),因此得到的结果会被打乱。前面展示的解决方案可避免出现这个问题。
另外,这个函数的通用化很强——不必绑定在只能对列表进行处理。比如,如果想读一个文件,去除其中重复的文本行,只需这样处理:
with open(somefile, 'r') as f:
for line in dedupe(f):
...
这个必须点赞👍