列表去重是Python中常用的处理方式,任何编程场景都可能遇到列表去重的需求。有很多方法可以删除重复列表。本文将一一讲解,并比较它们的性能。我们先创建一些简单的数据,生成100万个0到99的随机数:fromrandomimportrandrangeDUPLICATES=[randrange(100)for_inrange(1000000)]接下来试试4种去重方法中最简单直观的方法:1.新建一个数组,遍历原数组,如果值不在新数组中,则将其添加到新数组中。#第一个方法defeasy_way():unique=[]foreelementinDUPLICATES:ifelementnotinunique:unique.append(element)returnunique进入ipython,使用timeit计算其去重耗时:%timeiteasy_way()#1.16s±137msperloop(mean±std.dev.of7runs,1loopeach)平均耗时约1.16秒,但在本例中我们使用数组作为存储对象。事实上,如果我们将其改为一个集合来存储去重结果,性能会快很多:defeasy_way():unique=set()forelementinDUPLICATES:ifelementnotinunique:unique.add(element)returnunique%timeiteasy_way()#48.4ms±11.6msperloop(mean±std.dev.of7runs,10loopseach)平均耗时约48毫秒,提升明显。这是因为集合和数组的内部数据结构完全不同,集合使用哈希表,所以速度会比列表快很多,但缺点是乱序。接下来看第二种方法:2.直接把数组转成集合,再转回数组:#第二种去重方法deffast_way()returnlist(set(DUPLICATES))耗时:%timeitfast_way()#14.2ms±1.73msperloop(mean±std.dev.of7runs,100loopseach)平均需要14毫秒。这种去重方式是最快的,但是正如前面所说,集合是无序的。将数组转换为集合后,转换为列表会丢失原始列表的顺序。如果需要保留原来的数组顺序,这种方法不可取,怎么办?3.保留数组原序并去重使用dict.fromkeys()函数保留数组原序并去重:defsave_order():returnlist(dict.fromkeys(DUPLICATES))当然比简单的时间会长一点使用集合去重:%timeitsave_order()#39.5ms±8.66msperloop(mean±std.dev.of7runs,10loopseach)平均耗时39.5毫秒,我觉得是可以接受的耗时,毕竟orderof原始数组被保留。但是,dict.fromkeys()仅在Python3.6及更高版本中受支持。如果你是Python3.6以下的版本,不妨考虑第四种方式。4.ListsbelowPython3.6keepingorderanddeduplication在Python3.6以下,其实有一个fromkeys函数,不过是collections提供的:fromcollectionsimportOrderedDictdefsave_order_below_py36():returnlist(OrderedDict.fromkeys(DUPLICATES))time-consuming:%timeitsave_order_below_py36()#71.8ms±16.9msperloop(mean±std.dev.of7runs,10loopseach)平均耗时72毫秒左右,比Python3.6内置的dict.fromkeys()要慢,因为OrderedDict是在实现纯蟒蛇。[Responsibleeditor:ZhaoNingningTEL:(010)68476606]
