删除序列相同元素并保持顺序
怎样在一个序列上面保持元素顺序的同时消除重复的值?
首先,删除重复元素,我们第一时间肯定想到集合,因为集合无重复元素。但是,集合是无序的,题目要求序列保持元素顺序。
方法一:
1#删除重复元素
2a = [2,3,2,4,5,4,1,6,9,7,1,8]
3emtpylist = []
4for el in a:
5 print(el)
6 if el in emtpylist:
7 continue
8 else:
9 emtpylist.append(el)
10print(emtpylist) # print [2, 3, 4, 5, 1, 6, 9, 7, 8]
方法二:
1def NoRepeats(data):
2 tem= set()
3 for el in data:
4 if el in tem:
5 continue #当存在时,直接进行下一循环,不同添加,也不用生成
6 else:
7 tem.add(el)
8 yield el #只有执行else:才进行生成
9
10data = a = [2,3,2,4,5,4,1,6,9,7,1,8]
11generator = NoRepeats(data)
12for i in generator:
13 print(i,end=" ") #print 2 3 4 5 1 6 9 7 8
方法三:
1def NoRepeat2(data):
2 tem = set()
3 for el in data:
4 if el not in tem: #这里判断not in
5 tem.add(el)
6 yield tem #这里使用生成器,当然可以在前面新建空列表,在这里保存数据到列表中
以上方法适用于列表元素是hashbale可哈希数据类型,当元素不可哈希时,则使用set()方法不用了。
1a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
2print("set",set(a)) #TypeError: unhashable type: 'dict'
上面代码报错:TypeError: unhashable type: 'dict'。
这时候需要将元素转换成可哈希类型。然后判断是否重复,剔除重复的,然后重新生成不可哈希数据类型输出。定义一个函数,定义一个转换不可哈希的函数。
在这里假设一个简单的例子:字典中的元素key统一都是x,y的情况,不讨论其他键。
1a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4},{'x':1, 'y':3}]
我们将a中元素转变成可哈希类型元组:
1a = [(1,2),(1,3),(1,2),(2,4),(1,3)]
然后验证下,转变成集合,是否可以消除重复元素:
1#判断元组是否可哈希,可消除重复
2a = [(1,2),(1,3),(1,2),(2,4),(1,3)]
3print(set(a))
可见,可以消除重复元素,但是顺序是乱序。因此,可以通过生成器改变乱序。具体代码如下:
1def NoRepeat3(data,convert=None):
2 tem = set()
3 for el in data:
4 #不可哈希
5 val = convert(el) #利用convert函数将字典转换成可哈希的元组类型。value值变动
6 if val not in tem:
7 tem.add(val)
8 yield val
9data = [{'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
10key = lambda d : (d["x"],d['y']) #转变为可哈希内容
11generator = NoRepeat3(data,convert= key)
12newData = [] #定义一个新列表,重新保存处理后的数据
13for val1,val2 in generator:
14 x,y=val1,val2
15 val = {"x":val1,"y":val2}
16 newData.append(val)
17print("消除重复元素前",data)
18print("消除重复元素后",newData)
书中的方法简单:
1def dedupe(items, key=None):
2 seen = set()
3 for item in items:
4 val = item if key is None else key(item)
5 print(val)
6 if val not in seen:
7 print(item)
8 yield item #这里返回的是集合里不存在的转换后的元组,这里字典不可哈希,无法添加到集合中
9 #[{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]
10 seen.add(val)
11
12a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
13print(list(dedupe(a, key=lambda d: (d['x'],d['y']))))
上面通过将字典转换为元组,然后元组是可哈希类型,可以添加到集合中,利用集合的无重复性,判断转换后元组是否存在集合中,不存在就添加到集合中,同时打印该元组转换之前的字典,这些操作都放置在一个for循环执行,保持同步。同时针对生成器打印,不一定非要用for循环遍历,可以通过list(generator)转换的方法,将生成器内生成所有的元素,转换成list()列表内的元素。
1print(list(dedupe(a, key=lambda d: d['x']))) #筛选所有x为相同点的字典,y不管
2#print [{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]