Поиск неповторимых элементов в списке не работает

Я хотел найти неповторимые элементы в списке, но я не могу понять, почему это не происходит в разделе ниже кода.

>>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
>>> for i in d:
... if d.count(i) == 1:
... d.remove(i)
... 
>>> d
[1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b', 6, 3]

6 и 3 должны быть удалены. где as, если я использую

d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c']

Я получаю правильный ответ. Пожалуйста, объясните, что происходит, я смущен!!!

Я использую python 2.7.5.

5 ответов

Удаление элементов списка во время итерации по нему никогда не является хорошей идеей. Соответствующий способ сделать это - использовать collections.Counter с список:

>>> from collections import Counter
>>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6, 'f', 3]
>>> # Use items() instead of iteritems() in Python 3
>>> [k for (k,v) in Counter(d).iteritems() if v > 1]
['a', 1, 2, 'b', 4]

Если вы хотите сохранить повторяющиеся элементы в том порядке, в котором они отображаются в вашем списке:

>>> keep = {k for (k,v) in Counter(d).iteritems() if v > 1}
>>> [x for x in d if x in keep]
[1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b']

Я попытаюсь объяснить, почему ваш подход не работает. Чтобы понять, почему некоторые элементы не удаляются, как они должны быть, представьте, что мы хотим удалить все b из списка [a, b, b, c] во время цикла. Это будет выглядеть примерно так:

+-----------------------+
| a | b | b | c |
+-----------------------+
 ^ (first iteration)
+-----------------------+
| a | b | b | c |
+-----------------------+
 ^ (next iteration: we found a 'b' -- remove it)
+-----------------------+
| a | | b | c |
+-----------------------+
 ^ (removed b)
+-----------------+
| a | b | c |
+-----------------+
 ^ (shift subsequent elements down to fill vacancy)
+-----------------+
| a | b | c |
+-----------------+
 ^ (next iteration)

Обратите внимание, что мы пропустили второй b! Как только мы удалили первый b, элементы были сдвинуты вниз, и наш for -loop, следовательно, не смог коснуться каждого элемента списка. То же самое происходит в вашем коде.


Лучше использовать collections.Counter():

>>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
>>> from collections import Counter
>>> [k for k, v in Counter(d).iteritems() if v > 1]
['a', 1, 2, 'b', 4]

Также смотрите соответствующую тему:


Я просто подумал, что добавлю свой метод с установленным пониманием, если кто-то заинтересован.

>>> d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
>>> d = list({x for x in d if d.count(x) > 1})
>>> print d
['a', 1, 2, 'b', 4]

Python 2.7 и выше, я считаю, что для набора функций понятий.


Вы также можете сделать следующее:

data=[1,2,3,4,1,2,3,1,2,1,5,6]
 first_list=[]
 second_list=[]
 for i in data:
 if data.count(i)==1:
 first_list.append(i)
 else:
 second_list.append(i)
 print (second_list)

Результат

[1, 2, 3, 1, 2, 3, 1, 2, 1]


Спасибо за все ответы и комментарии!

Подумал какое-то время и получил еще один ответ по-своему, я написал код. Итак, я публикую его.

d = [1, 2, 1, 2, 4, 4, 5, 'a', 'b', 'a', 'b', 'c', 6,'f',3]
e = d[:] # just a bit of trick/spice
>>> for i in d:
... if d.count(i) == 1:
... e.remove(i)
... 
>>> e
[1, 2, 1, 2, 4, 4, 'a', 'b', 'a', 'b']

@arshajii, Ваше объяснение привело меня к этому трюку. Спасибо!

licensed under cc by-sa 3.0 with attribution.