Don't modify a list while iterating over it, it will mess you up every time:
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)
- First, you remove four
2s. Two are right at the beginning, so that puts you at the first 1.
- Then you advance one when you get the next
i from listy, putting you at the first 3.
- Then you remove two
3s. The first is right there, so that puts you at the first 4.
- Then you advance one again. The
2 is gone already, so this puts you at the second 1.
- You then delete both
1s; this moves you forward two spaces. The 2 and 3 are gone, so this puts you at the 5.
- You advance one, this moves you off the end of the list so the loop is over.
If what you want is to print each item only once, you can use the simple set method, or you could use the 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
Which extends the basic set version to allow you to specify a special way to compare items.
If you want to know which items are only in the list once:
listy2 = filter(lambda i: listy.count(i) == 1, listy)
listy2 now has all the single occurrences.
If you don't like the lambda, just do:
def getsingles(listy):
def singles(i):
return listy.count(i) == 1
return singles
then:
listy2 = filter(getsingles(listy), listy)
This makes a special function that will tell you which items are in listy only once.