python删除列表重复项_从一个Python列表中删除重复项,根据i删除其他列表

Zip将三个列表放在一起,根据第一个元素取消验证,然后解压缩:from operator import itemgetter

from more_itertools import unique_everseen

abc = zip(a, b, c)

abc_unique = unique_everseen(abc, key=itemgetter(0))

a, b, c = zip(*abc_unique)

这是一种很常见的模式。每当你想在一堆列表(或其他iterable)上执行lock step中的任何操作时,都可以将它们压缩在一起并循环处理结果。在

另外,如果从3个列表增加到42个(“如果列表数量增加,这可能会变得很麻烦。”),那么扩展这个列表是很简单的:

^{pr2}$

一旦你掌握了zip的诀窍,“不合格”是唯一困难的部分,所以让我来解释一下。在

您现有的代码通过在new_A中搜索每个元素来检查是否看到了每个元素。由于new_A是一个列表,这意味着如果你有N个元素,其中M个元素是唯一的,那么平均来说,你将对这N个元素中的每一个元素进行M/2比较。加上一些大的数字,NM/2就相当大了,比如100万个值,其中一半是唯一的,你要做2500亿个比较。在

为了避免这个二次时间,可以使用set。set可以测试一个元素在常数时间内的成员资格,而不是线性时间。所以,不是2500亿次比较,而是100万次哈希查找。在

如果不需要维护顺序或装饰流程取消对值的修饰,只需将列表复制到set中,就可以完成了。如果需要修饰,可以使用dict而不是set(键作为dict键,其他所有内容都隐藏在值中)。为了保持顺序,您可以使用OrderedDict,但在这一点上,只需并排使用list和set就更容易了。例如,对代码的最小更改是:new_A_set = set()

new_A = []

new_B = []

new_C = []

for i in range(len(A)):

if A[i] not in new_A_set:

new_A_set.add(A[i])

new_A.append(A[i])

new_B.append(B[i])

new_C.append(C[i])

但这是可以概括的,而且应该是,特别是如果你打算从3个列表扩展到全部列表的话。在

recipes in the ^{} documentation包含一个名为unique_everseen的函数,它准确地概括了我们想要的。您可以复制并粘贴到您的代码中,自己编写一个简化版本,或者pip install more-itertools并使用其他人的实现(如上所述)。在

帕德莱坎宁厄姆问道:how efficient is zip(*unique_everseen(zip(a, b, c), key=itemgetter(0)))?

如果有N个元素,M唯一,那就是O(N)时间和O(M)空间。在

事实上,它实际上在做与上面的10行版本相同的工作。在这两种情况下,循环中唯一不明显微不足道的工作是key in seen和seen.add(key),由于这两个操作都是set的常数时间摊销的,这意味着整个过程都是O(N)时间。实际上,对于N=1000000, M=100000,两个版本大约是278ms和297ms(我忘了哪个是哪个),而二次版本的时间是分钟。你也许可以将其微优化到250毫秒左右,但是很难想象你会需要这样的情况,但是用PyPy而不是CPython来运行它,或者用Cython或C编写它,或者对它进行numpy化,或者得到一台更快的计算机,或者并行化它,都不会有什么好处。在

至于空间,显式的版本让它变得非常明显。像任何可以想象的非变异算法一样,我们在原始列表的同时得到了三个new_Foo列表,我们还添加了相同大小的new_A_set。因为所有这些都是长度M,那就是4米的空间。我们可以通过一次传递来获得指数,然后再做同样的事情,穆無的回答是:indices = set(zip(*unique_everseen(enumerate(a), key=itemgetter(1))[0])

a = [a[index] for index in indices]

b = [b[index] for index in indices]

c = [c[index] for index in indices]

但是没有比这更低的方法了;你必须至少有一个集合和一个长度列表M在线性时间内对长度列表N进行不求证。在

如果您真的需要节省空间,您可以在适当的地方对这三个列表进行变异。但这要复杂得多,速度也慢一些(虽然仍然是线性的)。在

另外,值得注意的是zip版本的另一个优点:它适用于任何iterable。你可以给它提供三个懒惰的迭代器,它不必急于实例化它们。我不认为在2米空间内是可行的,但在3米空间也不难:indices, a = zip(*unique_everseen(enumerate(a), key=itemgetter(1))

indices = set(indices)

b = [value for index, value in enumerate(b) if index in indices]

c = [value for index, value in enumerate(c) if index in indices]

*请注意,del c[i]将使其成为二次函数,因为deletin从列表中间的g需要线性时间。幸运的是,{cdm><23个数量级的很快就可以移动到,您必须用一个sentinel替换每个重复的元素,然后在第二次循环中遍历列表,这样每个元素只能移动一次,这比不可变版本慢50%。在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值