Python过滤列表只留下出现一次的对象

Dan*_*ell 6 python list filter

我想过滤这个清单,

l = [0,1,1,2,2]

只离开,

[0].

我正在努力以'pythonic'方式做到这一点:o)没有嵌套循环可能吗?

Ale*_*lli 12

你需要两个循环(或等效的循环和listcomp,如下所示),但不是嵌套的循环:

import collections
d = collections.defaultdict(int)
for x in L: d[x] += 1
L[:] = [x for x in L if d[x] == 1]
Run Code Online (Sandbox Code Playgroud)

此解决方案假定列表项是可清除的,即它们可用作dicts,集合成员等的索引.

OP表示他们关心对象IDENTITY而不是VALUE(因此,例如两个值[1,2,3相等但可能不相同的子列表不会被视为重复).如果这是真的的话,那么这段代码是可用的,只需更换d[x]d[id(x)]中两次出现,它适用于任何类型的列表L.对象的工作

可变对象(列表,字符串,集合......)通常不可清除,因此不能以这种方式使用.用户定义的对象是在默认情况下可哈希(含hash(x) == id(x)),除非他们的类定义比较特殊的方法(__eq__,__cmp__,...),在这种情况下他们是哈希的当且仅当他们班还定义了一个__hash__方法.

如果列表L的项目不是可哈希的,但都是不平等可比的(因此排序),你不关心列表内的顺序,你可以在时间执行任务O(N log N)的第一个列表进行排序,然后应用itertools.groupby(差不多,但不太像另一个答案所暗示的那样).

其他方法,逐渐降低性能和增加通用性,当你关心列表的原始顺序时,可以处理不可变的可排序的数据(制作一个排序的副本,并在第二个循环中检查其上的重复bisect- 也是O(N)记录N)但速度稍慢),并且对象的唯一适用属性是它们的相等性(在最极端的情况下无法避免可怕的O(N**2)性能).

如果OP可以澄清哪种情况适用于他的具体问题,我将很乐意提供帮助(特别是,如果他的物品是可以清洗的,我上面已经给出的代码应该足够了;-).


sep*_*p2k 9

[x for x in the_list if the_list.count(x)==1]
Run Code Online (Sandbox Code Playgroud)

虽然那仍然是幕后的嵌套循环.

  • Alex的解决方案可能更快,但我认为这更优雅.;-) (3认同)

mha*_*wke 8

这是另一种字典导向方式:

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
Run Code Online (Sandbox Code Playgroud)