遍历列表并删除重复元素时的循环问题

1 投票
8 回答
4704 浏览
提问于 2025-04-17 00:00

我想遍历一个列表,然后把那些出现超过一次的项目去掉,这样在用for循环打印的时候就不会重复打印了。

可是,有些只出现一次的项目似乎也受到了影响,我搞不清楚为什么。

任何建议都会非常感谢。

示例输出:

listy = [2,2,1,3,4,2,1,2,3,4,5]
for i in listy:
  if listy.count(i)>1:
    print i, listy.count(i)
    while i in listy: listy.remove(i)
  else:
    print i, listy.count(i)

输出结果:

 2 4
 3 2
 1 2

这样就完全忽略了4和5。

8 个回答

1

在我遇到的所有编程语言中,边遍历一个列表边修改它都是个坏主意。我建议:不要这么做。这里有一些更好的方法。

使用 set 来找出唯一出现的元素

source = [2,2,1,3,4,2,1,2,3,4,5]
for s in set(source):
    print s

这样你就能得到:

>>> source = [2,2,1,3,4,2,1,2,3,4,5]
>>> for s in set(source):
...     print s
... 
1
2
3
4
5

如果你想要计数,使用 defaultdict

from collections import defaultdict
d = defaultdict(int)
source = [2,2,1,3,4,2,1,2,3,4,5]
for s in source:
    d[s] += 1

for k, v in d.iteritems():
    print k, v

你会得到这个:

>>> for k, v in d.iteritems():
...     print k, v
... 
1 2
2 4
3 2
4 2
5 1

如果你想要排序的结果,使用 sortoperator

import operator
for k, v in sorted(d.iteritems(), key=operator.itemgetter(1)):
    print k, v

你会得到这个:

>>> import operator
>>> for k, v in sorted(d.iteritems(), key=operator.itemgetter(1)):
...     print k, v
... 
5 1
1 2
3 2
4 2
2 4
3

你遇到的问题是因为在遍历一个列表的时候,同时对这个列表进行了修改。

如果你不在乎输出的顺序,也不在乎数量的话,可以直接使用集合(set):

>>> listy = [2,2,1,3,4,2,1,2,3,4,5]
>>> print set(listy)
set([1, 2, 3, 4, 5])

如果你在乎数量,那就可以使用标准库中的 collections 模块里的 Counter 类:

>>> import collections
>>> collections.Counter(listy)
Counter({2: 4, 1: 2, 3: 2, 4: 2, 5: 1})
>>> c = collections.Counter(listy)
>>> for item in c.iteritems():
...     print "%i has a count of %i" % item
... 
1 has a count of 2
2 has a count of 4
3 has a count of 2
4 has a count of 2
5 has a count of 1

如果你既在乎顺序又在乎数量,那你就需要再建立一个新的列表:

>>> checked = []
>>> counts = []
>>> for item in listy: 
>>>     if item not in checked: 
>>>         checked.append(item) 
>>>         counts.append(listy.count(item))
>>> print zip(checked, counts)
... [(2, 4), (1, 2), (3, 2), (4, 2), (5, 1)]

当然,这种方法是效率最低的。

如果你不打算以后再使用数量信息,那就不需要 counts 这个列表:

listy = [2,2,1,3,4,2,1,2,3,4,5]
checked = set()
for item in listy: 
    # "continue early" looks better when there is lots of code for
    # handling the other case
    if item in checked:     
        continue

    checked.add(item) 
    print item, listy.count(item)
5

在遍历一个列表的时候,不应该对这个列表进行修改。这样做可能会导致一些意想不到的问题。下面的代码应该可以正常工作:

listy = [2,2,1,3,4,2,1,2,3,4,5]
found = set()
for i in listy:
    if not i in found:
        print i, listy.count(i)
        found.add(i)

运行后的结果是:

2 4
1 2
3 2
4 2
5 1

撰写回答