从Python列表中删除项

从Python列表中删除项,python,list,numbers,Python,List,Numbers,如何从列表中删除相同的项目? 说 A=[1,2,3,8,7,8,8,7,6] 我想删除所有8个 我该怎么做?如果编号不符合顺序?最简单的方法是建立一个新列表,其中包含所有不是8的项目。例如: In [13]: A= [1, 2, 3, 8, 7, 8, 8, 7, 6] In [14]: [i for i in A if i!=8] Out[14]: [1, 2, 3, 7, 7, 6] In [15]: filter(lambda i: i!=8, A) Out[15]: [1, 2, 3

如何从列表中删除相同的项目? 说

A=[1,2,3,8,7,8,8,7,6]

我想删除所有8个
我该怎么做?如果编号不符合顺序?

最简单的方法是建立一个新列表,其中包含所有不是
8
的项目。例如:

In [13]: A= [1, 2, 3, 8, 7, 8, 8, 7, 6]

In [14]: [i for i in A if i!=8]
Out[14]: [1, 2, 3, 7, 7, 6]

In [15]: filter(lambda i: i!=8, A)
Out[15]: [1, 2, 3, 7, 7, 6]
B=[item for item in A if item != 8]

如果您确实希望就地执行此操作(例如,因为某个其他对象引用了与
a
相同的列表,并且您希望该其他对象查看更改),您可以。但这更棘手。例如,如果按索引删除,则必须在某一点上向后移动(因为当删除第一个
8
时,所有后面的
8
都有新的索引,因此始终必须先删除最后一个索引):

或者您可以继续尝试
删除
,直到失败,但这既丑陋又缓慢:

while True:
    try:
        A.remove(8)
    except ValueError:
        break
事实上,您最好还是创建一个新列表,然后将
a
变为新列表的副本:

A[:]=[item for item in A if item != 8]

为了进行性能测试,我对所有建议的答案进行了测试。测试的算法包括:

  • 复习:我在这个答案中的第一个就地算法
  • 克里斯·巴克的第一个算法
  • 幻灯片:克里斯·巴克的第二种算法(固定版本)
  • genexpr:我的最后一个算法,但是使用genexpr而不是listcomp
  • 我的最后一个算法
  • filterer:我的最后一个算法,但使用filter(注意,这意味着它在2.x中构建了一个列表,但在3.x中构建了一个类似genexpr的迭代器)
请注意,如果您实际上不需要变异
A
——通常也不需要,您可以将名称重新绑定到副本,然后变异算法变得更加简单和快速。但我没有在这里测试

我也没有完全测试“while-True:remove-until-error”算法,或者Chris Barker在评论中建议的变化,因为它们显然要慢得多,不值得测试。然而,一个非常快速的测试表明,变化大约是预期的2倍,并且在几乎任何测试用例中,两者都比其他任何东西慢几个数量级

无论如何,测试从长度为100K或1M的随机列表中删除0(重复次数为1/10),值范围为0到16、256或65536(不同值越少,删除的命中率越高)

如果您使用的是CPython,listcomp版本总是最快的,尤其是当N较大时。在使用PyPy时,当N很大而M很小时,就地算法可以击败它,但在这种情况下,它们都非常快。奇特的滑动算法消除了其他就地算法的二次行为,但对于简单的情况,它也会减慢速度,因此,实际上没有一个地方是明确的赢家。(这也是迄今为止最复杂的,这可能是为什么它是第一次尝试中不正确的。)如果你绝对确信你只会删除一小部分拷贝,而你在使用PyPy,那么考虑一下WeldEL解决方案;在任何其他用例中,或者当您不确定用例时,我会使用listcomp

          64-bit python CPython 3.3.0
          16 values    256 values   65536 values
          100K  1000K  100K  1000K  100K  1000K
revind    0.188 17.3   0.085 1.23   0.074 0.080
whiledel  0.324 19.3   0.206 1.36   0.199 0.203
slide     0.091  0.54  0.097 0.54   0.095 0.538
genepxr   0.094  0.11  0.100 0.11   0.099 0.108
listcomp  0.070  0.08  0.073 0.08   0.071 0.079
filterer  0.081  0.09  0.080 0.09   0.835 0.088

          64-bit python CPython 2.7.2
          16 values    256 values   65536 values
          100K  1000K  100K  1000K  100K  1000K
revind    0.198 17.1   0.089 1.23   0.088 0.955
whiledel  0.345 19.8   0.233 1.36   0.234 0.243
slide     0.095  0.54  0.099 0.55   0.095 0.551
genepxr   0.092  0.11  0.097 0.11   0.107 0.116
listcomp  0.091  0.09  0.099 0.08   0.105 0.114
filterer  0.122  0.23  0.132 0.09   0.135 0.150

          64-bit python PyPy 1.9.0 (Python 2.7.2)
          16 values    256 values   65536 values
          100K  1000K  100K  1000K  100K  1000K
revind    0.266 28.5   0.027 1.97   0.018 0.013
whiledel  0.281 30.2   0.023 1.94   0.034 0.009
slide     0.022  0.39  0.015 0.022  0.006 0.018
genepxr   0.089  0.13  0.087 0.154  0.089 0.147
listcomp  0.052  0.08  0.057 0.073  0.052 0.073
filterer  0.054  0.07  0.053 0.078  0.048 0.074

很难预测幻灯片的性能。在大N/小M的情况下,你会期望它会在风吹走的同时吹走,但实际上速度较慢。但如果你仔细想想:这个算法有效地用N个简单的拷贝代替了M个线性移动。前者是O(NM),后者是O(N),C中循环的乘数(或者更好的是,在
memmove
)比Python中循环的乘数小得多,除非N/M很大(在这一点上,所有的解决方案都非常快,几乎不重要)。因此,做M个Python循环和NM C循环可以轻松击败做N个Python循环。

简单的方法是建立一个新的列表,包含所有不是
8
的项目。例如:

B=[item for item in A if item != 8]

如果您确实希望就地执行此操作(例如,因为某个其他对象引用了与
a
相同的列表,并且您希望该其他对象查看更改),您可以。但这更棘手。例如,如果按索引删除,则必须在某一点上向后移动(因为当删除第一个
8
时,所有后面的
8
都有新的索引,因此始终必须先删除最后一个索引):

或者您可以继续尝试
删除
,直到失败,但这既丑陋又缓慢:

while True:
    try:
        A.remove(8)
    except ValueError:
        break
事实上,您最好还是创建一个新列表,然后将
a
变为新列表的副本:

A[:]=[item for item in A if item != 8]

为了进行性能测试,我对所有建议的答案进行了测试。测试的算法包括:

  • 复习:我在这个答案中的第一个就地算法
  • 克里斯·巴克的第一个算法
  • 幻灯片:克里斯·巴克的第二种算法(固定版本)
  • genexpr:我的最后一个算法,但是使用genexpr而不是listcomp
  • 我的最后一个算法
  • filterer:我的最后一个算法,但使用filter(注意,这意味着它在2.x中构建了一个列表,但在3.x中构建了一个类似genexpr的迭代器)
请注意,如果您实际上不需要变异
A
——通常也不需要,您可以将名称重新绑定到副本,然后变异算法变得更加简单和快速。但我没有在这里测试

我也没有完全测试“while-True:remove-until-error”算法,或者Chris Barker在评论中建议的变化,因为它们显然要慢得多,不值得测试。然而,一个非常快速的测试表明,变化大约是预期的2倍,并且在几乎任何测试用例中,两者都比其他任何东西慢几个数量级

无论如何,该测试将从长度为100K或1M的随机列表中删除0(重复次数为1/10),其值范围为0到16、256或65536(较少的不同值,
def remove_all_from_list(L, n):
    # indices takes *worse-case* O(N) space, but typical-case much less
    indices = [i for i, x in enumerate(L) if x==n]
    indices_seen = 0
    num_indices = len(indices)
    for i in xrange(len(L)):
        while (indices_seen < num_indices and 
            i + indices_seen == indices[indices_seen]):
            indices_seen += 1
        if i+indices_seen >= len(L):
            break
        L[i] = L[i+indices_seen]            
    L[-indices_seen:] = []
import random
L = range(30)*10000
random.shuffle(L)
from copy import copy

for fn in [remove_1, remove_2, remove_3, remove_4, remove_5, remove_6]:
    print fn.__name__
    %timeit fn(copy(L), 8)

remove_1 # listcomp
10 loops, best of 3: 39.1 ms per loop
remove_2 # revind
1 loops, best of 3: 1.7 s per loop
remove_3 # try: remove; except: break
1 loops, best of 3: 65.7 s per loop
remove_4 # while n in L: L.remove(n)
1 loops, best of 3: 129 s per loop
remove_5 # whiledel
1 loops, best of 3: 1.87 s per loop
remove_6 # slide
1 loops, best of 3: 227 ms per loop