Вдобавок к тому, что некоторые другие сказали от моего понимания.NET и Java лучше в выделении памяти. Например, они могут уплотнить память, поскольку она фрагментируется, в то время как C++ не может (исходно, но она может при использовании умного сборщика "мусора").
Вот еще один способ, ориентированный на словарь:
l = [0, 1, 1, 2, 2]
d = {}
for i in l: d[i] = i in d
[k for k in d if not d[k]] # unordered, loop over the dictionary
[k for k in l if not d[k]] # ordered, loop over the original list
Вам понадобятся два цикла (или, что эквивалентно, цикл и listcomp, как показано ниже), но не вложенные:
import collections
d = collections.defaultdict(int)
for x in L: d[x] += 1
L[:] = [x for x in L if d[x] == 1]
Это решение предполагает, что элементы списка хэшируемые , то есть что они могут использоваться в качестве индексов в словах, членах наборов и т. Д.
OP указывает, что они заботятся об ИДЕНТИЧНОСТИ объекта и не ЗНАЧЕНИЕ (так, например, два подсписка, каждый из которых имеет значение [1,2,3
, которые равны, но могут не быть идентичными, не будут считаться дубликатами). Если это действительно так, то этот код можно использовать, просто замените d [x]
на d [id (x)]
в обоих случаях, и он будет работать для ЛЮБЫХ типов объектов в list L.
Изменяемые объекты (списки, словари, наборы и т. д.) обычно не хешируются и поэтому не могут использоваться подобным образом. Пользовательские объекты по умолчанию хешируются (с hash (x) == id (x)
), если их класс не определяет специальные методы сравнения ( __ eq __
,
[x for x in the_list if the_list.count(x)==1]
Хотя это все еще скрытый за кадром вложенный цикл.
>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) is 1]
[0]
>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) == 1]
[0]
l = [0,1,2,1,2]
def justonce( l ):
once = set()
more = set()
for x in l:
if x not in more:
if x in once:
more.add(x)
once.remove( x )
else:
once.add( x )
return once
print justonce( l )
В том же духе, что и в решении Алекса, вы можете использовать Counter / multiset (встроенный в 2.7, рецепты совместимы с 2.5 и выше), чтобы сделать то же самое:
In [1]: from counter import Counter
In [2]: L = [0, 1, 1, 2, 2]
In [3]: multiset = Counter(L)
In [4]: [x for x in L if multiset[x] == 1]
Out[4]: [0]
Я думаю, что фактическое время довольно интересно:
Ответ Алекса:
python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import collections" "d = collections.defaultdict(int)" "for x in l: d[x] += 1" "l[:] = [x for x in l if d[x] == 1]"
1000 loops, best of 3: 370 usec per loop
Моя:
python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "once = set()" "more = set()" "for x in l:" " if x not in more:" " if x in once:" " more.add(x)" " once.remove( x )" " else:" " once.add( x )"
1000 loops, best of 3: 275 usec per loop
версия sepp2k O (n ** 2), чтобы продемонстрировать, почему важна компетентность; -)
python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "[x for x in l if l.count(x)==1]"
100 loops, best of 3: 16 msec per loop
Роберто + сортировка:
python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import itertools" "[elem[0] for elem in itertools.groupby(sorted(l)) if elem[1].next()== 0]"
1000 loops, best of 3: 316 usec per loop
mhawke's:
python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "d = {}" "for i in l: d[i] = d.has_key(i)" "[k for k in d.keys() if not d[k]]"
1000 loops, best of 3: 251 usec per loop
Мне нравится последний, умный и быстрый; -)