删除序列相同元素并保持顺序

怎样在一个序列上面保持元素顺序的同时消除重复的值?

首先,删除重复元素,我们第一时间肯定想到集合,因为集合无重复元素。但是,集合是无序的,题目要求序列保持元素顺序。

方法一:

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}]