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

时间:2009-08-16 22:13:05

标签: python list filter

我想过滤此列表,

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

只离开,

[0]。

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

9 个答案:

答案 0 :(得分: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]

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

OP表示他们关心对象IDENTITY而不是VALUE(因此,例如两个值相等但[1,2,3的子列表相同但可能不相同的子列表不会被视为重复)。如果确实如此,则此代码可用,只需在两次出现中将d[x]替换为d[id(x)],它将适用于列表L中的任何类型的对象。

可变对象(列表,字符串,集合......)通常不可清除,因此不能以这种方式使用。默认情况下,用户定义的对象是可以使用的(hash(x) == id(x)),除非它们的类定义了比较特殊方法(__eq____cmp__,...),在这种情况下,它们只能是可以清除的如果他们的类也定义了__hash__方法。

如果列表的项目不可清,但 可用于不等式(因此可排序),并且您不关心它们在列表中的顺序,您可以及时执行任务{ {1}}首先对列表进行排序,然后应用O(N log N)(几乎但不完全按照另一个答案建议的方式)。

当你关心列表的原始顺序时,可以处理不可变的可排序的其他方法(制作一个已排序的副本,在第二个循环中,在{{1}的帮助下检查重复的顺序 - 也是O(N log N)但速度稍慢),并且对象的唯一适用属性是它们的相等性(无法避免最大程度上的可怕O(N ** 2)性能一般情况)。

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

答案 1 :(得分:9)

[x for x in the_list if the_list.count(x)==1]

虽然这仍然是幕后的嵌套循环。

答案 2 :(得分: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

答案 3 :(得分:4)

与Alex的解决方案一样,您可以使用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]

答案 4 :(得分:3)

>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) is 1]
[0]

答案 5 :(得分:3)

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 )

答案 6 :(得分:1)

我认为实际时间很有意思:

亚历克斯回答:

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)版本,以证明为什么compexity很重要; - )

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

Roberto's + sorted:

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的:

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

我喜欢最后一个,聪明又快速; - )

答案 7 :(得分:1)

>>> l = [0,1,1,2,2]
>>> [x for x in l if l.count(x) == 1]
[0]

答案 8 :(得分:0)

类似的问题出现在编码问题上。我的解决方案不是最优雅,但它是我的第一个自我融合的解决方案,因此希望与大家分享!

testlist = [2,4,6,8,10,2,6,10]

def unique_elements(testlist):
    final_list = []
    for x in testlist:
        if testlist.count(x)==1:
            final_list.append(x)
        else:
            pass
    print(final_list)

unique_elements(testlist)