【发布时间】:2011-01-13 21:50:15
【问题描述】:
我有一个 Python 列表:
k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]
我想从中删除重复的元素。如果它不是我可以使用set 的列表的普通列表。但不幸的是,该列表不可散列并且无法制作列表集。只有元组。所以我可以将所有列表转换为元组,然后使用 set 并返回到列表。但这并不快。
如何以最有效的方式做到这一点?
以上列表的结果应该是:
k = [[5, 6, 2], [1, 2], [3], [4]]
我不在乎维持秩序。
注意:this question 类似,但不是我需要的。搜索了 SO,但没有找到完全重复的内容。
基准测试:
import itertools, time
class Timer(object):
def __init__(self, name=None):
self.name = name
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
if self.name:
print '[%s]' % self.name,
print 'Elapsed: %s' % (time.time() - self.tstart)
k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [5, 2], [6], [8], [9]] * 5
N = 100000
print len(k)
with Timer('set'):
for i in xrange(N):
kt = [tuple(i) for i in k]
skt = set(kt)
kk = [list(i) for i in skt]
with Timer('sort'):
for i in xrange(N):
ks = sorted(k)
dedup = [ks[i] for i in xrange(len(ks)) if i == 0 or ks[i] != ks[i-1]]
with Timer('groupby'):
for i in xrange(N):
k = sorted(k)
dedup = list(k for k, _ in itertools.groupby(k))
with Timer('loop in'):
for i in xrange(N):
new_k = []
for elem in k:
if elem not in new_k:
new_k.append(elem)
“循环输入”(二次方法)对于短列表来说是最快的。对于长列表,除了 groupby 方法之外,它比所有人都快。这有意义吗?
对于短列表(代码中的那个),100000 次迭代:
[set] Elapsed: 1.3900001049
[sort] Elapsed: 0.891000032425
[groupby] Elapsed: 0.780999898911
[loop in] Elapsed: 0.578000068665
对于更长的列表(代码中的那个重复5次):
[set] Elapsed: 3.68700003624
[sort] Elapsed: 3.43799996376
[groupby] Elapsed: 1.03099989891
[loop in] Elapsed: 1.85900020599
【问题讨论】:
-
“这不快”,您是说您已经计时并且它对您的应用程序来说还不够快,还是您认为它不够快?
-
@Torsten,这似乎是抄袭太多而不是聪明的方法。对不起,直觉。将列表复制到元组,然后复制到集合,然后返回到列表列表(再次将元组复制到列表)
-
@zaharpopov:这不是 Python 的工作方式,不会复制,只是现有元素的新容器(尽管对于 int,它几乎相同)
-
1.使用排序的方法的时间被缩减了,因为“k”被反弹到排序的变体。 2. 最后一种方法更快,因为您生成测试数据的方式最多为您留下 4 个不同的元素。试试看。比如 K = [[int(u) for u in str(random.randrange(1, 1000))] for _ in range(100)]
-
@Torsten:解决了,谢谢。但即使 10 列表中只有一个重复项,循环方法仍然很快
标签: python