我想迭代列表,并删除多次计数的项目,因此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.
答案 0 :(得分: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
答案 1 :(得分:3)
您遇到问题的原因是您在迭代时修改了列表。
如果您不关心项目在输出中的显示顺序而不关心计数,您只需使用一组:
>>> listy = [2,2,1,3,4,2,1,2,3,4,5]
>>> print set(listy)
set([1, 2, 3, 4, 5])
如果 关心计数,请使用标准库中Counter
模块的collections
类:
>>> 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)
答案 2 :(得分:1)
迭代时不要修改列表,每次都会弄乱你:
listy = [2,2,1,3,4,2,1,2,3,4,5]
# * * * Get hit
for i in listy:
print i
if listy.count(i) > 1:
print i, listy.count(i), 'item and occurences'
while i in listy: listy.remove(i)
else:
print i, listy.count(i)
2
。两个在开头就是正确的,所以这会让你处于第一个1
。i
获得下一个listy
,然后将您放在第一个3
时,您就前进一个。3
。第一个就在那里,这样就可以让你进入第一个4
。2
已经消失,因此这会让您进入第二个1
。1
个;这会让你前进两个空间。 2
和3
已消失,因此您可以访问5
。如果你想要的只是打印每个项目一次,你可以使用简单的set
方法,或者你可以使用itertools
unique_everseen
recipe:
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
扩展了基本set
版本,允许您指定比较项目的特殊方式。
如果您想知道哪些项目只在列表中一次:
listy2 = filter(lambda i: listy.count(i) == 1, listy)
listy2
现在已经发生了所有单次事件。
如果您不喜欢lambda,请执行以下操作:
def getsingles(listy):
def singles(i):
return listy.count(i) == 1
return singles
然后:
listy2 = filter(getsingles(listy), listy)
这是一个特殊功能,可以告诉您哪些项目只在listy
一次。
答案 3 :(得分:1)
你得到的行为的原因在于:
http://docs.python.org/reference/compound_stmts.html#index-811
我认为更好的解决方案是使用Counter的实例:
import random
from collections import Counter
li = [ random.randint(0,20) for i in xrange(30)]
c = Counter(li)
print c
print type(c)
res = [ k for k in c if c[k]==1]
print res
结果
Counter({8: 5, 0: 3, 4: 3, 9: 3, 2: 2, 5: 2, 11: 2, 3: 1, 6: 1, 10: 1, 12: 1, 15: 1, 16: 1, 17: 1, 18: 1, 19: 1, 20: 1})
<class 'collections.Counter'>
[3, 6, 10, 12, 15, 16, 17, 18, 19, 20]
另一个解决方案是在一个集合中添加读取元素,以便程序避免对已经看到的元素进行计数。
错误....我的解决方案是愚蠢的,你不想选择在列表中只出现一次的元素....
然后,我认为以下代码是正确的:
import random
from collections import Counter
listy = [ random.randint(0,20) for i in xrange(30)]
print 'listy==',listy
print
c = Counter(listy)
print c
print type(c)
print
slimmed_listy = []
for el in listy:
if el in c:
slimmed_listy.append(el)
print 'element',el,' count ==',c[el]
del c[el]
print
print 'slimmed_listy==',slimmed_listy
结果
listy== [13, 10, 1, 1, 13, 11, 18, 15, 3, 15, 12, 11, 15, 18, 11, 10, 14, 10, 20, 3, 18, 9, 11, 2, 19, 15, 5, 14, 1, 1]
Counter({1: 4, 11: 4, 15: 4, 10: 3, 18: 3, 3: 2, 13: 2, 14: 2, 2: 1, 5: 1, 9: 1, 12: 1, 19: 1, 20: 1})
<class 'collections.Counter'>
element 13 count == 2
element 10 count == 3
element 1 count == 4
element 11 count == 4
element 18 count == 3
element 15 count == 4
element 3 count == 2
element 12 count == 1
element 14 count == 2
element 20 count == 1
element 9 count == 1
element 2 count == 1
element 19 count == 1
element 5 count == 1
slimmed_listy== [13, 10, 1, 11, 18, 15, 3, 12, 14, 20, 9, 2, 19, 5]
如果您不希望结果按 listy 的顺序排列,则代码会更简单
如果您只想打印,我建议:
import random
from collections import Counter
listy = [ random.randint(0,20) for i in xrange(30)]
print 'listy==',listy
print
def gener(li):
c = Counter(li)
for el in li:
if el in c:
yield el,c[el]
del c[el]
print '\n'.join('element %4s count %4s' % x for x in gener(listy))
结果
listy== [16, 2, 4, 9, 15, 19, 1, 1, 3, 5, 12, 15, 12, 3, 17, 13, 8, 11, 4, 6, 15, 1, 0, 1, 3, 3, 6, 5, 0, 8]
element 16 count 1
element 2 count 1
element 4 count 2
element 9 count 1
element 15 count 3
element 19 count 1
element 1 count 4
element 3 count 4
element 5 count 2
element 12 count 2
element 17 count 1
element 13 count 1
element 8 count 2
element 11 count 1
element 6 count 2
element 0 count 2
答案 4 :(得分: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
如果您希望对结果进行排序,请使用sort
和operator
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
答案 5 :(得分:0)
我不确定迭代列表并同时删除元素是否是个好主意。如果你真的只想输出所有项目及其出现次数,我会这样做:
listy = [2,2,1,3,4,2,1,2,3,4,5]
listx = []
listc = []
for i in listy:
if not i in listx:
listx += [i]
listc += [listy.count(i)]
for x, c in zip(listx, listc):
print x, c
答案 6 :(得分:0)
就像agf所说的那样,在迭代它时修改列表会导致问题。您可以使用while
和pop
来解决您的代码:
single_occurrences = []
while listy:
i = listy.pop(0)
count = listy.count(i)+1
if count > 1:
print i, count
while i in listy: listy.remove(i)
else:
print i, count
single_occurrences.append(i)
输出:
2 4
1 2
3 2
4 2
5 1
答案 7 :(得分:0)
这样做的一种方法是创建一个结果列表并测试测试值是否在其中:
res=[]
listy = [2,2,1,3,4,2,1,2,3,4,5]
for i in listy:
if listy.count(i)>1 and i not in res:
res.append(i)
for i in res:
print i, listy.count(i)
结果:
2 4
1 2
3 2
4 2