首先明确2个概念:
1、如果一个对象是可哈希的,那么在它的生存期内必须是不可变的。例如整数、浮点数、字符串、元组都是不可变的。
2、集合中的元素是唯一的(可哈希的),但是顺序可变。
先考虑序列中的元素是不可变
直接使用set()转换:
a = [1, 5, 2, 1, 9, 5, 10]
set(a)
Out[3]: {1, 2, 5, 9, 10} # 虽去重了,但是元素的顺序变了
迭代序列元素,并使用 yield
语句,来保持元素的顺序:
def dedupe(items):
""" 在当序列中的元素是可hash的时候 """
seen = set()
for item in items:
if item not in seen:
yield item # 使用生成器,返回唯一的元素
seen.add(item)
a = [1, 5, 2, 1, 9, 5, 10]
list(dedupe(a))
Out[5]: [1, 5, 2, 9, 10]
如果序列的元素是不可哈希的呢?下面来实现更通用的解决方案
def dedupe(items, key=None):
"""
1、当序列中的元素是不可hash的,去除重复项
2、使用set集合的目的是利用集合中的元素是唯一的这一特点,来保证返回值item中元素唯一,起到去重作用
:param items:
:param key: 指定一个函数用来将序列中的元素转换为可hash的类型
:return:
"""
seen = set()
for item in items:
val = item if key is None else key(item)
if val not in seen:
yield item # 返回item
seen.add(val) # seen集合,确保相同的val值的item元素对象不会被返回
# 元素是不可hash的
a = [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
list(dedupe(a, key=lambda d: (d['x'], d['y']))) # 根据x, y的value值去重
Out[7]: [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
list(dedupe(a, key=lambda d: d['x'])) # 根据x的value值去重
Out[9]: [{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]
# 元素是可hash的
a = [1, 5, 2, 1, 9, 5, 10]
list(dedupe(a))
Out[11]: [1, 5, 2, 9, 10]
总结:
1、可以使用集合和生成器来实现序列去重且保持元素顺序不变;
2、生成器yield
语句返回后,暂停挂起,执行后续操作后,再循环;
3、dedupe()函数模仿了内置函数sorted()
、min()
、max()
对key函数的使用方式。
网友评论