查找列表中是否重复某些内容的最有效方法是什么?

时间:2016-06-21 09:39:16

标签: python list python-2.7

我们说我有一个清单:

l = ['a', 'b', 'c', 'd', 'e', 'f', 'e']

如您所见,重复索引4和6。我的问题是:查看列表中是否有重复内容的最有效方法是什么?

选项1:

output = len(set(l)) != len(l):

如果输出为false,则不止一次存在一个值。

选项2:

output = True
for i in l:
  if l.count(i) > 1:
    output = False

如果输出为false,则不止一次存在一个值。

问题:

  1. 最有效的方法是什么?

  2. 如何计算这两个(或更多?)选项的O表示法?

  3. 谢谢!

5 个答案:

答案 0 :(得分:6)

关于计算O()值:

选项1执行4项操作:创建一个集合,获取其长度,获取列表的长度,然后比较它们。其中,创建集合必须至少为O(n),其他集合最多为O,因此效率由集合创建主导。我相信Python中的集合的实现使得插入平均需要O(1),因此这应该是 O(n)

选项2包含一个循环。在循环内部,您调用l.count,它遍历整个列表以计算项目发生的次数。所以每次迭代都是O(n)。循环本身为循环中的每个项运行,因此n次。总效率 O(n * n)

是否存在比选项1更快的内容取决于您的真实数据的特征,其长度,重复的可能性,不同项目的数量(如果它们都是小写字母,那么任何长度> 26的列表都有重复,检查真的很快)等等。它无法回答。但是O(n)真的很难被击败,如果重复很少,那么通常必须检查所有项目,而且必须已经是O(n)。

答案 1 :(得分:3)

循环并收集一组中看到的项目。

一旦找到第一个副本,请注意break。在extrem(没有重复项)中,您将循环列表一次并构建一个包含每个列表项的集合。

l = ['a', 'b', 'c', 'd', 'e', 'f', 'e']
seen = set()

for x in l:
    if x in seen:
        print("seen '{}' already, done".format(x))
        # As soon as find find the first duplicate, break.
        break
    seen.add(x)

输出:

seen 'e' already, done

答案 2 :(得分:2)

选项1很快。

因为set方法使用散列和len方法需要O(1)时间。

因此,这是任何人都可以做到的最快方式。

https://wiki.python.org/moin/TimeComplexity

答案 3 :(得分:2)

这是我能想到的最简单的速度比较。

选项1基本上归结为从列表中创建一个集合:

(dev) go|c:\srv\tmp> python -m timeit "set(range(100))"
100000 loops, best of 3: 5.48 usec per loop

而选项2归结为遍历列表并进行成员资格测试(以及我跳过的集合添加):

(dev) go|c:\srv\tmp> python -m timeit "for i in range(100): i in set()"
10000 loops, best of 3: 22.1 usec per loop

(dev) go|c:\srv\tmp> python -m timeit "for i in range(50): i in set()"
100000 loops, best of 3: 10 usec per loop

(dev) go|c:\srv\tmp> python -m timeit "for i in range(25): i in set()"
100000 loops, best of 3: 5.2 usec per loop

所以,第一个副本必须 大多数 25%进入选项2的列表才能更快,并且添加第二个集合操作将进行比较选项2更糟糕。

答案 4 :(得分:0)

以精美的字典格式提供所有信息的解决方案如下:

from collections import Counter

l = ['a', 'b', 'c', 'd', 'e', 'f', 'e']

# Get how many of each exist.
counts = Counter(l)
# Looks like this:
# Counter({'e': 2, 'd': 1, 'c': 1, 'f': 1, 'a': 1, 'b': 1})

# Print letters which have 2 or more instances.
for i in counts:
    if counts[i] > 1:
        print(i, counts[i])

一旦你有了这个,就可以在不变的时间内访问各个字典元素。虽然打印每个副本仍然需要O(n)时间。这个,以及也是O(n)的计数器的初始成本使得O(2n)接近于O(n)。